Why is it that,
scala> List(1,2,3,4).iterator.map((x: Int) => println(x))
does not print out
1
2
3
4
while
List(1,2,3,4).map((x: Int) => println(x))
List(1,2,3,4).foreach((x: Int) => println(x))
List(1,2,3,4).iterator.foreach((x: Int) => println(x))
all do?
In other words, why is it that a map on a iterator that maps type T to Unit and has side effects unable to show those side effects?
Edit:
Also why does the following invocation of lazyMap actually computes the new iterator (provide the complete new iterator) from beginning to end if iterator is lazy?
def lazyMap[T, U](coll: Iterable[T], f: T => U) = new Iterable[U] {
def iterator = coll.iterator map f
}
scala> lazyMap(List(1,2,3,4), (x: Int) => x + 1)
res4: java.lang.Object with Iterable[Int] = (2, 3, 4, 5)
Once you do that you should be able to iterate over the map, print the map elements, etc. In summary, I hope these examples of iterating a Scala Map have been helpful.
In Scala, Map is a data structure used to map from keys to values. The Scala Standard Library has implemented the Map structure on both immutable and mutable collections for multiple use cases. Immutable maps are the default and are more commonly used. In this tutorial, we’ll look at how Maps work to understand how to iterate over them.
The iterator method is utilized to give an iterator. Return Type: It returns a non-empty iterator for non-empty map and returns an empty iterator for empty map. Writing code in comment?
The iterator method is utilized to give an iterator. Return Type: It returns a non-empty iterator for non-empty map and returns an empty iterator for empty map.
Cause map on iterator is lazy and you need some strictness:
scala> List(1,2,3,4).iterator.map((x: Int) => println(x))
res0: Iterator[Unit] = non-empty iterator
// nothing actually happened yet, just remember to do this printing things
scala> res0.toList
1
2
3
4
res1: List[Unit] = List((), (), (), ())
When you doing foreach on iterator it is quite obvious that you're doing side effects, so lazyness will be undesired. I wouldn't said so about map.
UPD
As for your edit: the reason for such behaviour, is that there is implicit call of toString for statement result which in turn stricts the iterator -- try this code on your own:
scala> { lazyMap(List(1,2,3,4), {(x: Int) => println(x); x + 1}); 1 }
and you'll see that function f
is never called
The point of an Iterator is laziness. In other words, when you create an Iterator, it will not evaluate anything until you go to read the data. Here's what that looks like:
scala> val itr = List(1,2,3).iterator
itr: Iterator[Int] = non-empty iterator
Ok, we've got an iterator now. But it hasn't actually looked at the list yet.
scala> val mappedItr = itr.map((x: Int) => println(x))
mappedItr: Iterator[Unit] = non-empty iterator
Now we have a new Iterator. This one will, when data is accessed, apply the function that has been mapped. But we still haven't actually looked at the original list.
scala> mappedItr.next
1
This is the first time we have accessed data, so it is the first time that the Iterator has looked into the list. We called next
, so we got the first element. Since our iterator has a map
queued up, it applies the mapped function when we access that element. So we see the result of the function applied to the next
item.
We can do it again to get the next element:
scala> mappedItr.next
2
And, again, it evaluates the function only when it needs to, in order to give us the final result.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With