Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala Iterator with Map and For

Given:

val list = List("one","two","three")     
val it = list.toIterator

I can run:

list map ("_" +) -> List(_one, _two, _three)
for (i <- list) yield("_" + i) -> List(_one, _two, _three)

If I run the same on the iterator I get:

it map ("_" + ) -> Iterator[java.lang.String] = empty iterator
for (i <- it) yield("_" + i) -> Iterator[java.lang.String] = empty iterator

Shouldn't I get back another (non-empty) Iterator[String] after I run map/for on it?

like image 961
ssanj Avatar asked Feb 03 '11 05:02

ssanj


2 Answers

See Iterators.

There's an important difference between the foreach method on iterators and the same method on traversable collections: When called to an iterator, foreach will leave the iterator at its end when it is done. So calling next again on the same iterator will fail with a NoSuchElementException. By contrast, when called on on a collection, foreach leaves the number of elements in the collection unchanged (unless the passed function adds to removes elements, but this is discouraged, because it may lead to surprising results).

...

As you can see, after the call to it.map, the it iterator has advanced to its end.

like image 154
Eugene Yokota Avatar answered Sep 21 '22 15:09

Eugene Yokota


scala> def ints(n: Int): Stream[Int] = n #:: ints(n + 1)
ints: (n: Int)Stream[Int]

scala> val list = List("one","two","three")
list: List[java.lang.String] = List(one, two, three)

scala> val it = list.toIterator
it: Iterator[java.lang.String] = non-empty iterator

scala> it map ("_" + )
res24: Iterator[java.lang.String] = non-empty iterator

scala> it map ("_" + )
res25: Iterator[java.lang.String] = non-empty iterator

scala> for (i <- it) yield("_" + i)
res26: Iterator[java.lang.String] = non-empty iterator

Maybe you used your iterator?

scala> res26.foreach{println}
_one
_two
_three

scala> res26
res28: Iterator[java.lang.String] = empty iterator

Since iterators are stateful and not resettable, once you used it, it is empty and can't be used again.

Instead, you can use views:

scala> val v = list.view
v: java.lang.Object with scala.collection.SeqView[java.lang.String,List[java.lang.String]] = SeqView(one, two, three)

scala> v map ("_" + )
res29: scala.collection.SeqView[java.lang.String,Seq[_]] = SeqViewM(...)

scala> for (i <- v) yield("_" + i)
res30: scala.collection.SeqView[java.lang.String,Seq[_]] = SeqViewM(...)

scala> res29.foreach{println}
_one
_two
_three

scala> res29
res32: scala.collection.SeqView[java.lang.String,Seq[_]] = SeqViewM(...)

scala> res29.foreach{println}
_one
_two
_three
like image 39
IttayD Avatar answered Sep 20 '22 15:09

IttayD