Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

consume items from a scala Iterator

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?

like image 747
jglatre Avatar asked Oct 01 '11 10:10

jglatre


People also ask

What does iterator do in Scala?

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.

Is Scala iterator lazy?

Unlike operations directly on a concrete collection like List , operations on Iterator are lazy.

What is one way to iterate Scala?

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.

What is iterable in Scala?

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.


2 Answers

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))
like image 88
retronym Avatar answered Sep 19 '22 12:09

retronym


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.

like image 27
jglatre Avatar answered Sep 17 '22 12:09

jglatre