是否可以使用'yield'生成'Iterator'而不是Scala中的列表?

时间:2010-12-24 09:34:20

标签: scala yield continue yield-return yield-keyword

是否可以在不评估每个值的情况下使用yield作为迭代器?

这很容易实现复杂的列表生成,然后你需要将它转换为Iterator,因为你不需要一些结果......

3 个答案:

答案 0 :(得分:49)

不确定。实际上,非严格性有三种选择,我在下面列出。对于示例,假设:

val list = List.range(1, 10)
def compute(n: Int) = {
    println("Computing "+n)
    n * 2
}
  1. StreamStream是一个懒惰的评估列表。它将按需计算值,但一旦计算出值,它将不会重新计算值。如果您多次重用流的某些部分,它将非常有用。例如,运行下面的代码将打印“计算1”,“计算2”和“计算3”,每次一次。

    val stream = for (n <- list.toStream) yield compute(n)
    val third = stream(2)
    println("%d %d" format (third, stream(2)))
    
  2. 视图。视图是基础集合上的操作组合。在检查视图时,检查的每个元素都是按需计算的。如果你随机访问视图,它是最有用的,但它永远不会只看其中的一小部分。例如,运行下面的代码将打印“计算3”两次,没有别的(除了结果之外)。

    val view = for (n <- list.view) yield compute(n)
    val third = view(2)
    println("%d %d" format (third, view(2)))
    
  3. IteratorIterator是用来懒散地浏览集合的东西。人们可以把它想象成一个“一次性”的收藏品,可以这么说。它既不会重新计算也不会存储任何元素 - 一旦元素被“计算”,它就不能再次使用。由于这个原因,使用起来有点棘手,但鉴于这些限制,它是最有效的。例如,以下示例需要不同,因为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

您可以使用flatMapmapfilter方法对任何类型进行理解。您还可以使用视图

scala> for { i <- res0.view } yield foo(i)
res3: scala.collection.SeqView[String,Seq[_]] = SeqViewM(...)

在任何一种情况下,评估都是非严格的......

scala> res3.head
Eval: 1
res4: String = 1Foo