如何合并迭代器解析器

Juh*_*uh_ 7 iterator scala

我有Iterator[(A1,B1)]两个功能

  • fA: (Iterator[A1]) => Iterator[A2]
  • fB: (Iterator[B1]) => Iterator[B2].

是否有可能在fAB: (Iterator[(A1,B1)]) => Iterator[(A2,B2)]没有将迭代器转换为Seq 的情况下进行转换?

编辑

以下两个答案都很好.我选择了@ Aivean的答案,因为代码更简单,它使用专门的scala数据结构(Stream).

唯一的缺点是stackoverfow限制,但对于大多数用例来说它应该不是问题.如果你的迭代器非常(非常)长,那么@ Alexey的解决方案应该是首选的.

Aiv*_*ean 2

我的实现要简单得多:

def iterUnzip[A1, B1, A2, B2](it: Iterator[(A1, B1)],
                           fA: (Iterator[A1]) => Iterator[A2],
                           fB: (Iterator[B1]) => Iterator[B2]) =
  it.toStream match {
    case s => fA(s.map(_._1).toIterator).zip(fB(s.map(_._2).toIterator))
  }
Run Code Online (Sandbox Code Playgroud)

这个想法是将迭代器转换为流。Stream在 Scala 中是惰性的,但也提供了记忆化功能。这有效地提供了与 @AlexeyRomanov 的解决方案相同的缓冲机制,但更简洁。唯一的缺点是,Stream与显式队列相反,将记忆元素存储在堆栈上,因此如果以不均匀的速率fA生成fB元素,则可能会出现 StackOverflow 异常。

测试评估确实是惰性的:

val iter = Stream.from(0).map(x => (x, x + 1))
  .map(x => {println("fetched: " + x); x}).take(5).toIterator

iterUnzip(
  iter,
  (_:Iterator[Int]).flatMap(x => List(x, x)),
  (_:Iterator[Int]).map(_ + 1)
).toList
Run Code Online (Sandbox Code Playgroud)

结果:

fetched: (0,1)
iter: Iterator[(Int, Int)] = non-empty iterator

fetched: (1,2)
fetched: (2,3)
fetched: (3,4)
fetched: (4,5)
res0: List[(Int, Int)] = List((0,2), (0,3), (1,4), (1,5), (2,6))
Run Code Online (Sandbox Code Playgroud)

我还相当努力地尝试通过生成不均匀的迭代器来获得 StackOverflow 异常,但失败了。

val iter = Stream.from(0).map(x => (x, x + 1)).take(10000000).toIterator
iterUnzip(
    iter,
    (_:Iterator[Int]).flatMap(x => List.fill(1000000)(x)),
    (_:Iterator[Int]).map(_ + 1)
  ).size
Run Code Online (Sandbox Code Playgroud)

工作良好-Xss5m并产生:

res10: Int = 10000000
Run Code Online (Sandbox Code Playgroud)

因此,总的来说,这是一个相当不错且简洁的解决方案,除非您有一些极端的用例。