I'm confused about behavior of method take
in trait Iterator
. It seems that it doesn't consume items. Here is an example:
scala> Iterator(1,2,3)
res0: Iterator[Int] = non-empty iterator
scala> res0 take 2 toArray
res1: Array[Int] = Array(1, 2)
scala> res0.next
res2: Int = 1
Apparently step 2 consumes two items, but in step 3 the Iterator
is still at first item. Looking at the implementation, I can't see any kind of copying or buffering, just a new Iterator
which delegates to the underlying one. How could it be possible? How can I manage to really consume n items?
An iterator is a way to access elements of a collection one-by-one. It resembles to a collection in terms of syntax but works differently in terms of functionality. An iterator defined for any collection does not load the entire collection into the memory but loads elements one after the other.
Unlike operations directly on a concrete collection like List , operations on Iterator are lazy.
Two important methods in Scala Iterator are next() and hasNext. hasNext will tell if there is another element to return, while next() will return that element.
Iterable: A base trait for iterable collections. This is a base trait for all Scala collections that define an iterator method to step through one-by-one the collection's elements.
The iterator in question is defined in IndexedSeqLike#Elements
(source). A ticket was recently filed about the the inconsistent behaviour of take
across different iterator implementations.
To really consume N items, call Iterator#next
N times.
You might want to consider using Stream
, which is a lazy (like Iterator
), but is also immutable (unlike Iterator
).
scala> val s = Stream(1, 2, 3)
s: scala.collection.immutable.Stream[Int] = Stream(1, ?)
scala> s.take(2).toList
res43: List[Int] = List(1, 2)
scala> s.take(2).toList
res44: List[Int] = List(1, 2)
scala> s.drop(2).toList
res45: List[Int] = List(3)
scala> {val (s1, s2) = s.splitAt(2); (s1.toList, s2.toList)}
res46: (List[Int], List[Int]) = (List(1, 2),List(3))
Thanks guys.
This is my solution to consume bunches of items from an Iterator
:
implicit def consumable(i: Iterator[_]) = new {
def next(n: Int) = {
(for (_ <- 1 to n) yield i.next()).iterator
}
def skip(n: Int) {
(1 to n).foreach(_ => i.next())
}
}
any comments will be welcome.
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