Oscar Broman
Oscar Broman

Reputation: 1127

for-loop behavior when iterating a Set instead of a List

How does the behavior of the for-loop change when a Set instance is given instead of a List instance?

Fiddle: http://scalafiddle.net/console/67ed94744426295f96268f4ac1881b46

Code:

case class Book(title: String, authors: List[String]) {}

val books = List(
  Book("Book 1", List("Author 1", "Author 2")),
  Book("Book 2", List("Author 2")),
  Book("Book 3", List("Author 3")),
  Book("Book 4", List("Author 4"))
)

def authorsWithMultipleBooks(books: Iterable[Book]) =
  for {
    b1 <- books
    b2 <- books
    if b1 != b2
    a1 <- b1.authors
    a2 <- b2.authors
    if a1 == a2
  } yield a1

println(authorsWithMultipleBooks(books))
// Output: List(Author 2, Author 2)
println(authorsWithMultipleBooks(books.toSet))
// Output: Set(Author 2)

Upvotes: 0

Views: 47

Answers (1)

Gabriele Petronella
Gabriele Petronella

Reputation: 108101

In both cases you yield "Author 2" twice, but since Set only holds one istance of each element, the second time you yield it it doesn't change the set.

So the for loop doesn't change in its behavior, the only thing acting differently is the insertion in the resulting collection, which - being a set - discards duplicate insertions.

Here's an example to further clarify the idea:

scala> val authors = List("Author 1", "Author 2", "Author 3")
authors: List[String] = List(Author 1, Author 2, Author 3)

scala> for {
     | _ <- authors
     | } yield "Author 2"
res8: List[String] = List(Author 2, Author 2, Author 2)

scala> val authorsSet = authors.toSet
authorsSet: scala.collection.immutable.Set[String] = Set(Author 1, Author 2, Author 3)

scala> for {
     | _ <- authorsSet
     | } yield "Author 2"
res10: scala.collection.immutable.Set[String] = Set(Author 2)

Upvotes: 3

Related Questions