如何折叠Scala迭代器并获得延迟计算的序列作为结果?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何折叠Scala迭代器并获得延迟计算的序列作为结果?相关的知识,希望对你有一定的参考价值。

我有一个字符串迭代器,其中每个字符串可以是"H"(标题)或"D"(详细信息)。我想将此迭代器拆分为多个块,其中每个块均以一个标头开头,并且可以具有0到许多详细信息。

我知道如何解决将所有内容加载到内存中的问题。例如,下面的代码:

Seq("H","D","D","D","H","D","H","H","D","D","H","D").toIterator
  .foldLeft(List[List[String]]())((acc, x) => x match 
    case "H" => List(x) :: acc
    case "D" => (x :: acc.head) :: acc.tail )
  .map(_.reverse)
  .reverse

返回5个块-List(List(H, D, D, D), List(H, D), List(H), List(H, D, D), List(H, D))-这是我想要的。

但是,我想要List[List[String]]而不是结果中的Iterator[List[String]]或某种其他结构,让我可以懒惰地评估结果,并且如果整个迭代器都被消耗,则不要将整个输入加载到内存中 ,我只想一次仅将正在消耗的块加载到内存中(例如:当我调用iterator.next时)。

如何修改上面的代码以获得所需的结果?

编辑:我特别需要在Scala 2.11中使用它,因为我使用的是它所遵循的环境。很高兴也接受其他版本的答案。

答案

如果使用Scala 2.13.x,则可以通过展开原始Iterator来创建新的Iterator。>

import scala.collection.mutable.ListBuffer

val data = Seq("H","D","D","D","H","D","H","H","D","D","H","D").iterator

val rslt = Iterator.unfold(data.buffered)itr =>
  if (itr.hasNext) 
    val lb = ListBuffer(itr.next())
    while (itr.hasNext && itr.head == "D")
      lb += itr.next()
    Some((lb.toList, itr))
   else None

测试:

rslt.next()   //res0: List[String] = List(H, D, D, D)
rslt.next()   //res1: List[String] = List(H, D)
rslt.next()   //res2: List[String] = List(H)
rslt.next()   //res3: List[String] = List(H, D, D)
rslt.next()   //res4: List[String] = List(H, D)
rslt.hasNext  //res5: Boolean = false

以上是关于如何折叠Scala迭代器并获得延迟计算的序列作为结果?的主要内容,如果未能解决你的问题,请参考以下文章

迭代 RDD 迭代器并应用限制时,Spark 似乎没有调用 hasNext

Scala:如何在循环中组合数据帧

在 Scala 中迭代 Java 集合

使用 Akka 进行 Scala 折叠

java - 如何在java中的map上保留两个迭代器并在没有ConcurrentModificationException的情况下删除它们之间的键

如何计算所有折叠的平均分类报告?