gpt4 book ai didi

Scala View 过滤器不懒惰?

转载 作者:行者123 更新时间:2023-12-05 00:19:31 26 4
gpt4 key购买 nike

在尝试理解流、迭代器和集合 View 之间的差异时,我偶然发现了以下奇怪的行为。

这里的代码(映射和过滤器只是打印它们的输入并保持不变):

object ArrayViewTest {
def main(args: Array[String]) {
val array = Array.range(1,10)

print("stream-map-head: ")
array.toStream.map(x => {print(x); x}).head

print("\nstream-filter-head: ")
array.toStream.filter(x => {print(x); true}).head

print("\niterator-map-head: ")
array.iterator.map(x => {print(x); x}).take(1).toArray

print("\niterator-filter-head: ")
array.iterator.filter(x => {print(x); true}).take(1).toArray

print("\nview-map-head: ")
array.view.map(x => {print(x); x}).head

print("\nview-filter-head: ")
array.view.filter(x => {print(x); true}).head
}
}

它的输出:
stream-map-head: 1
stream-filter-head: 1
iterator-map-head: 1
iterator-filter-head: 1
view-map-head: 1
view-filter-head: 123456789 // <------ WHY ?

为什么在 View 上调用的过滤器会处理整个数组?
我希望过滤器的评估只通过调用 head 驱动一次,就像在所有其他情况下一样,特别是就像在 View 上使用 map 一样。

我缺少哪种见解?

(评论的小问题,为什么迭代器没有头?)

编辑: scala.Array.range(1,10)scala.collection.mutable.ArraySeq.range(1,10)scala.collection.mutable.ArrayBuffer.range(1,10) 实现了同样奇怪的行为(就像这里的 scala.collection.mutable.StringBuilder.newBuilder.append("123456789") )。
但是,对于所有其他可变集合和所有不可变集合, View 上的过滤器按预期工作并输出 1

最佳答案

我认为它必须这样做Array是可变索引序列。它的 View 也是一个可变集合 :) 因此,当它创建一个 View 时,它会创建一个在原始集合和过滤集合之间映射的索引。懒惰地创建这个索引并没有真正意义,因为当有人请求第 i 个元素时,无论如何都可能遍历整个源数组。从某种意义上说,直到您调用 head 才会创建此索引,这仍然是懒惰的。 .这仍然没有在 Scala 文档中明确说明,乍一看似乎是一个错误。

对于迷你方面的问题,我认为是 head 的问题迭代器是人们期望的head成为纯函数,即您应该能够调用它 n 次并且每次都应该返回相同的结果。并且迭代器本质上是可变的数据结构,按照约定只能遍历一次。这可以通过缓存迭代器的第一个元素来克服,但我发现这非常令人困惑。

关于Scala View 过滤器不懒惰?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35719964/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com