【发布时间】:2012-12-11 04:29:15
【问题描述】:
有时我发现自己想在 Scala for 推导中对无限流执行嵌套迭代,但指定循环终止条件可能有点棘手。有没有更好的方法来做这种事情?
我想到的用例是我不一定预先知道我正在迭代的每个无限流中需要多少元素(但显然我知道它不会是无限数)。假设每个流的终止条件可能以某种复杂的方式依赖于 for 表达式中其他元素的值。
最初的想法是尝试将流终止条件写为 for 表达式中的 if 过滤子句,但是在循环嵌套无限流时会遇到问题,因为没有办法使第一个无限流上的迭代短路,最终导致 OutOfMemoryError。我理解为什么会这样,考虑到 for 表达式如何映射到 map、flatMap 和 withFilter 方法调用 -我的问题是做这种事情是否有更好的习语(也许根本不涉及 for 理解)。
为了给出一个有点人为的例子来说明刚刚描述的问题,请考虑以下(非常幼稚的)代码来生成数字 1 和 2 的所有配对:
val pairs = for {
i <- Stream.from(1)
if i < 3
j <- Stream.from(1)
if j < 3
}
yield (i, j)
pairs.take(2).toList
// result: List[(Int, Int)] = List((1,1), (1,2))
pairs.take(4).toList
// 'hoped for' result: List[(Int, Int)] = List((1,1), (1,2), (2,1), (2,2))
// actual result:
// java.lang.OutOfMemoryError: Java heap space
// at scala.collection.immutable.Stream$.from(Stream.scala:1105)
显然,在这个简单的示例中,可以通过将 if 过滤器移动到原始流上的 takeWhile 方法调用中轻松避免问题,如下所示:
val pairs = for {
i <- Stream.from(1).takeWhile(_ < 3)
j <- Stream.from(1).takeWhile(_ < 3)
}
yield (i, j)
但出于问题的目的,请想象一个更复杂的用例,其中流终止条件不能轻易移动到流表达式本身。
【问题讨论】:
标签: scala stream for-comprehension