Scala List of tuple becomes empty after for loop

Viewed 141

I have a Scala list of tuples, "params", which are of size 28. I want to loop through and print each element of the list, however, nothing is printed out. After finishing the for loop, I checked the size of the list, which now becomes 0.

I am new to scala and I could not figure this out after a long time googling.

val primes = List(11, 13, 17, 19, 2, 3, 5, 7)
val params = primes.combinations(2)
println(params.size)

for (param <- params) {
  print(param(0), param(1))
}
println(params.size)



3 Answers

combinations methods in List create an Iterator. Once the Iterator is consumed using methods like size, it will be empty.

From the docs

one should never use an iterator after calling a method on it.

If you comment out println(params.size), you can see that for loop is printing out the elements, but the last println(params.size) will remain as 0.

Complementing Johny's great answer:

Do you know how I can save the result from combination methods to use for later?

Well, as already suggested you can just toList
However, note there is a reason why combinations returns an Iterator and it is because the data can be too big, if you are okay with that then go ahead; but you may still take advantage of laziness.

For example, let's convert the inner lists into a tuples before collecting the results:

val params =
  primes
    .combinations(2)
    .collect {
      case a :: b :: Nil => (a, b)
    }.toList

In the same way, you may add extra steps in the chain like another map or a filter before doing the toList
Even better, if your end action is something like foreach(foo) then you do not even need to collect everything into a List

primes.combinations(2) returns Iterator.

Iterators are data structures that allow to iterate over a sequence of elements. They have a hasNext method for checking if there is a next element available, and a next method which returns the next element and discards it from the iterator.

So, it is like pointer to Iterable collection. Once you have done iteration you no longer will be able to iterate again.

When println(params.size) executed that time iteration completed while computing size and now params is pointing to end. Because of this for (param <- params) will be equivalent looping around empty collection.

There can 2 possible solution:

  1. Don't check the size before for loop.
  2. Convert iterator to Iterable e.g. list. params = primes.combinations(2).toList

To learn more about Iterator and Iterable refer What is the relation between Iterable and Iterator?

Related