【问题标题】:Is it possible to use 'yield' to generate 'Iterator' instead of a list in Scala?是否可以使用 'yield' 来生成 'Iterator' 而不是 Scala 中的列表?
【发布时间】:2011-05-30 08:28:46
【问题描述】:

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

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

【问题讨论】:

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


    【解决方案1】:

    当然。实际上,非严格性有三个选项,我在下面列出。对于示例,假设:

    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. 一个视图。视图是对基本集合的操作的组合。检查视图时,检查的每个元素都是按需计算的。如果您将随机访问视图,但只会查看其中的一小部分,这将是最有用的。例如,运行下面的代码将打印两次“Computing 3”,没有其他内容(嗯,除了结果)。

      val view = for (n <- list.view) yield compute(n)
      val third = view(2)
      println("%d %d" format (third, view(2)))
      
    3. IteratorIterator 是用来懒惰地浏览集合的东西。可以说,可以将其视为“一次性”集合。它既不会重新计算也不会存储任何元素——一旦一个元素被“计算”过,就不能再次使用它。因此使用起来有点棘手,但考虑到这些限制,它是最有效的。比如下面的例子就需要有所不同,因为Iterator不支持索引访问(这样写的话view会执行不好),下面的代码打印出“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))
      

    【讨论】:

      【解决方案2】:

      如果您想要惰性评估,请使用视图,请参阅 Views

      The Scala 2.8 Collections API 如果您要大量使用 Scala 集合,这本书是一本很棒的书。

      【讨论】:

        【解决方案3】:

        我有一个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-comprehensionIterator...

        scala> for { i <- res0.iterator } yield foo(i)
        res2: Iterator[java.lang.String] = non-empty iterator
        

        您可以通过 flatMapmapfilter 方法对任何类型使用 for 理解。你也可以使用 views:

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

        无论哪种情况,评估都是非严格的......

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2015-05-10
          • 1970-01-01
          • 2013-06-28
          • 1970-01-01
          • 1970-01-01
          • 2021-12-01
          • 2020-12-20
          相关资源
          最近更新 更多