How to use takeWhile with an Iterator in Scala
iteration, iterator, scala
Solution
With my other answer (which I've left separate as they are largely unrelated), I think you can implement `groupWhen` on `Iterator` as follows:
def groupWhen[A](itr: Iterator[A])(p: (A, A) => Boolean): Iterator[List[A]] = {
@annotation.tailrec
def groupWhen0(acc: Iterator[List[A]], itr: Iterator[A])(p: (A, A) => Boolean): Iterator[List[A]] = {
val (dup1, dup2) = itr.duplicate
val pref = ((dup1.sliding(2) takeWhile { case Seq(a1, a2) => p(a1, a2) }).zipWithIndex collect {
case (seq, 0) => seq
case (Seq(_, a), _) => Seq(a)
}).flatten.toList
val newAcc = if (pref.isEmpty) acc else acc ++ Iterator(pref)
if (dup2.nonEmpty)
groupWhen0(newAcc, dup2 drop (pref.length max 1))(p)
else newAcc
}
groupWhen0(Iterator.empty, itr)(p)
}
When I run it on an example:
println( groupWhen(List(1,1,1,1,3,4,3,2,2,2).iterator)(_ == _).toList )
I get `List(List(1, 1, 1, 1), List(2, 2, 2))`
Problem
I have a Iterator of elements and I want to consume them until a condition is met in the next element, like: ``` val it = List(1,1,1,1,2,2,2).iterator val res1 = it.takeWhile( _ == 1).toList val res2 = it.takeWhile(_ == 2).toList ``` `res1` gives an expected `List(1,1,1,1)` but `res2` returns `List(2,2)` because iterator had to check the element in position 4. I know that the list will be ordered so there is no point in traversing the whole list like `partition` does. I like to finish as soon as the condition is not met. Is there any clever way to do this with Iterators? I can not do a `toList` to the iterator because it comes from a very big file.