是否可以在不评估每个值的情况下使用 yield 作为迭代器?
当很容易实现复杂的列表生成时,这是一个常见的任务,然后你需要将它转换为Iterator
,因为你不需要一些结果......
是否可以在不评估每个值的情况下使用 yield 作为迭代器?
当很容易实现复杂的列表生成时,这是一个常见的任务,然后你需要将它转换为Iterator
,因为你不需要一些结果......
当然。实际上,非严格性有三个选项,我在下面列出。对于示例,假设:
val list = List.range(1, 10)
def compute(n: Int) = {
println("Computing "+n)
n * 2
}
Stream
. AStream
是一个惰性评估列表。它将按需计算值,但一旦计算出值,它就不会重新计算值。如果您将多次重复使用流的某些部分,则它是最有用的。例如,运行下面的代码将打印“计算 1”、“计算 2”和“计算 3”,各打印一次。
val stream = for (n <- list.toStream) yield compute(n)
val third = stream(2)
println("%d %d" format (third, stream(2)))
一个视图。视图是对基本集合的操作的组合。检查视图时,检查的每个元素都是按需计算的。如果您将随机访问视图,但只会查看其中的一小部分,这将是最有用的。例如,运行下面的代码将打印两次“Computing 3”,没有其他内容(嗯,除了结果)。
val view = for (n <- list.view) yield compute(n)
val third = view(2)
println("%d %d" format (third, view(2)))
Iterator
. AnIterator
是用来懒洋洋地浏览一个集合的东西。可以说,可以将其视为“一次性”集合。它既不会重新计算也不会存储任何元素——一旦一个元素被“计算”过,就不能再次使用它。因此使用起来有点棘手,但考虑到这些限制,它是最有效的。比如下面的例子就需要有所不同,因为Iterator
不支持索引访问(这样写的话视图性能会很差),下面的代码会打印出“Computing 1”、“Computing 2”、“Computing 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))
如果您想要惰性评估,请使用视图,请参阅Views。
如果您打算大量使用 Scala 集合,那么Scala 2.8 Collections API是一本很棒的读物。
我有一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
现在我将使用一个用于理解的Iterator
...
scala> for { i <- res0.iterator } yield foo(i)
res2: Iterator[java.lang.String] = non-empty iterator
您可以使用flatMap
,map
和filter
方法对任何类型使用 for 理解。您还可以使用视图:
scala> for { i <- res0.view } yield foo(i)
res3: scala.collection.SeqView[String,Seq[_]] = SeqViewM(...)
在任何一种情况下,评估都是非严格的......
scala> res3.head
Eval: 1
res4: String = 1Foo