ton*_*ian 9 iteration iterator scala
我有一个元素的迭代器,我想消耗它们,直到下一个元素满足条件,如:
val it = List(1,1,1,1,2,2,2).iterator
val res1 = it.takeWhile( _ == 1).toList
val res2 = it.takeWhile(_ == 2).toList
Run Code Online (Sandbox Code Playgroud)
res1给出一个预期List(1,1,1,1)但res2返回,List(2,2)因为迭代器必须检查位置4中的元素.
我知道列表将被订购,所以没有必要像遍历那样遍历整个列表partition.我希望在条件不满足时立即完成.是否有任何聪明的方法与迭代器一起做这个?我不能toList对迭代器做一个因为它来自一个非常大的文件.
我发现的最简单的解决方案:
val it = List(1,1,1,1,2,2,2).iterator
val (r1, it2) = it.span( _ == 1)
println(s"group taken is: ${r1.toList}\n rest is: ${it2.toList}")
Run Code Online (Sandbox Code Playgroud)
输出:
group taken is: List(1, 1, 1, 1)
rest is: List(2, 2, 2)
Run Code Online (Sandbox Code Playgroud)
很短,但进一步你必须使用新的迭代器。
对于任何不可变集合,它都是类似的:
根据我的其他答案(我将其分开,因为它们基本上不相关),我认为您可以groupWhen按Iterator如下方式实施:
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)
}
Run Code Online (Sandbox Code Playgroud)
当我在示例上运行它时:
println( groupWhen(List(1,1,1,1,3,4,3,2,2,2).iterator)(_ == _).toList )
Run Code Online (Sandbox Code Playgroud)
我明白了List(List(1, 1, 1, 1), List(2, 2, 2))