是否可以在不评估每个值的情况下使用yield作为迭代器?
这很容易实现复杂的列表生成,然后你需要将它转换为Iterator
,因为你不需要一些结果......
答案 0 :(得分:49)
不确定。实际上,非严格性有三种选择,我在下面列出。对于示例,假设:
val list = List.range(1, 10)
def compute(n: Int) = {
println("Computing "+n)
n * 2
}
Stream
。 Stream
是一个懒惰的评估列表。它将按需计算值,但一旦计算出值,它将不会重新计算值。如果您多次重用流的某些部分,它将非常有用。例如,运行下面的代码将打印“计算1”,“计算2”和“计算3”,每次一次。
val stream = for (n <- list.toStream) yield compute(n)
val third = stream(2)
println("%d %d" format (third, stream(2)))
视图。视图是基础集合上的操作组合。在检查视图时,检查的每个元素都是按需计算的。如果你随机访问视图,它是最有用的,但它永远不会只看其中的一小部分。例如,运行下面的代码将打印“计算3”两次,没有别的(除了结果之外)。
val view = for (n <- list.view) yield compute(n)
val third = view(2)
println("%d %d" format (third, view(2)))
Iterator
。 Iterator
是用来懒散地浏览集合的东西。人们可以把它想象成一个“一次性”的收藏品,可以这么说。它既不会重新计算也不会存储任何元素 - 一旦元素被“计算”,它就不能再次使用。由于这个原因,使用起来有点棘手,但鉴于这些限制,它是最有效的。例如,以下示例需要不同,因为Iterator
不支持索引访问(如果以这种方式编写,视图将执行得很糟糕),并且下面的代码打印“Computing 1”,“Computing 2”,“计算3“,”计算4“,”计算5“和”计算6“。此外,它最后会打印两个不同的数字。
val iterator = for (n <- list.iterator) yield compute(n)
val third = iterator.drop(2).next
println("%d %d" format (third, iterator.drop(2).next))
答案 1 :(得分:3)
如果您想进行延迟评估,请使用视图,请参阅 Views 。
如果您要使用Scala集合,The Scala 2.8 Collections API 是一个很棒的读物。
答案 2 :(得分:2)
我有List
...
scala> List(1, 2, 3)
res0: List[Int] = List(1, 2, 3)
功能 ...
scala> def foo(i : Int) : String = { println("Eval: " + i); i.toString + "Foo" }
foo: (i: Int)String
现在我将使用 for-comprehension 和Iterator
...
scala> for { i <- res0.iterator } yield foo(i)
res2: Iterator[java.lang.String] = non-empty iterator
您可以使用flatMap
,map
和filter
方法对任何类型进行理解。您还可以使用视图:
scala> for { i <- res0.view } yield foo(i)
res3: scala.collection.SeqView[String,Seq[_]] = SeqViewM(...)
在任何一种情况下,评估都是非严格的......
scala> res3.head
Eval: 1
res4: String = 1Foo