我有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的解决方案应该是首选的.
我的实现要简单得多:
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)
因此,总的来说,这是一个相当不错且简洁的解决方案,除非您有一些极端的用例。
| 归档时间: |
|
| 查看次数: |
168 次 |
| 最近记录: |