表达式

时间:2018-06-17 03:41:15

标签: scala scala-collections

这段scala代码将视图与for表达式中的严格List混合:

val list = List.range(1, 4)
def compute(n: Int) = {
  println("Computing "+n)
  n * 2
}

val view = for (n <- list.view; k<-List(1,2)) yield compute(n)
val x = view(0)

输出结果为:

Computing 1
Computing 1
Computing 2
Computing 2
Computing 3
Computing 3
Computing 1
Computing 1

我预计它应该只有最后两行&#34;计算1&#34;在输出中。为什么要急切地计算所有的价值?那为什么它会再次重新计算这些价值呢?

2 个答案:

答案 0 :(得分:0)

这里查看的是SeqView[Int,Seq[_]],它是不可变的,并在迭代时重新计算每个项目。

您可以通过明确使用.iterator

来访问第一个
@ view.iterator.next
Computing 1
Computing 1
res11: Int = 2

或明确地将其设为List(例如,如果您需要重用许多条目):

@ val view2: List[Int] = view.toList
Computing 1
Computing 1
Computing 2
Computing 2
Computing 3
Computing 3
view2: List[Int] = List(2, 2, 4, 4, 6, 6)

@ view2(0)
res13: Int = 2

答案 1 :(得分:0)

可以说,索引访问会强制计算视图。另外,请注意,您使用非懒惰的内容(list不是视图)对k进行平面映射。

比较以下内容:

// 0) Your example
val v0 = List.range(1, 4).view.flatMap(n => List(1,2).map(k => compute(n)))
v0(0) // Computing 1 
      // Computing 1
      // Computing 2
      // Computing 2
      // Computing 3
      // Computing 3
      // Computing 1
      // Computing 1

v0(0) // Computing 1
      // Computing 1

// 1) Your example, but access by head and not by index
val v1 = List.range(1, 4).view.flatMap(n => List(1,2).map(k => compute(n)))
v1.head // Computing 1 
        // Computing 1

// 2) Do not mix views and strict lists
val v2 = List.range(1, 4).view.flatMap(n => List(1,2).view.map(k => compute(n)))
v2(0) // Computing 1

关于示例0,请注意视图不像流;虽然流确实缓存了它们的结果,但是懒惰的视图却没有(它们只是在访问时懒得计算,即根据需要)。似乎索引访问需要计算整个列表,然后需要另一个计算来实际按索引访问元素。

您可能会问为什么示例2中的索引访问不会计算整个列表。这需要了解事物的运作方式;特别是,我们可以在以下摘录中看到示例0和示例2的方法调用的区别:

示例0

java.lang.Exception scala.collection.SeqViewLike$FlatMapped.$anonfun$index$1(SeqViewLike.scala:75)
    at scala.collection.SeqViewLike$FlatMapped.index(SeqViewLike.scala:74)
    at scala.collection.SeqViewLike$FlatMapped.index$(SeqViewLike.scala:71)
    at scala.collection.SeqViewLike$$anon$5.index$lzycompute(SeqViewLike.scala:197)
    at scala.collection.SeqViewLike$$anon$5.index(SeqViewLike.scala:197)
    at scala.collection.SeqViewLike$FlatMapped.length(SeqViewLike.scala:84)
    at scala.collection.SeqViewLike$FlatMapped.length$(SeqViewLike.scala:84)
    at scala.collection.SeqViewLike$$anon$5.length(SeqViewLike.scala:197)
    at scala.collection.SeqViewLike$FlatMapped.apply(SeqViewLike.scala:86)
    at scala.collection.SeqViewLike$FlatMapped.apply$(SeqViewLike.scala:85)
    at scala.collection.SeqViewLike$$anon$5.apply(SeqViewLike.scala:197)
    at scala.collection.immutable.List.foreach(List.scala:389)
Computing 1

示例2

java.lang.Exception scala.runtime.java8.JFunction1$mcII$sp.apply(JFunction1$mcII$sp.java:12)
    at scala.collection.SeqViewLike$Mapped.apply(SeqViewLike.scala:67)
    at scala.collection.SeqViewLike$Mapped.apply$(SeqViewLike.scala:67)
    at scala.collection.SeqViewLike$$anon$4.apply(SeqViewLike.scala:196)
    at scala.collection.SeqViewLike$FlatMapped.apply(SeqViewLike.scala:88)
    at scala.collection.SeqViewLike$FlatMapped.apply$(SeqViewLike.scala:85)
    at scala.collection.SeqViewLike$$anon$5.apply(SeqViewLike.scala:197)
    at scala.collection.immutable.List.foreach(List.scala:389)
Computing 1

特别是,您看到示例0导致调用Flatmapped.length(需要评估整个列表)。