[英]In Scala, what does "view" do?
具体来说,我在这里查看问题 1
http://pavelfatin.com/scala-for-project-euler/
列出的代码如下
val r = (1 until 1000).view.filter(n => n % 3 == 0 || n % 5 == 0).sum
我可以关注除“视图”之外的所有内容。 事实上,如果我取出视图,代码仍然可以编译并产生完全相同的答案。
View 生成一个惰性集合,因此对例如filter
的调用不会评估集合的每个元素。 元素只有在被显式访问后才会被评估。 现在sum
确实可以访问所有元素,但是通过view
调用filter
不会创建完整的 Vector。 (见史蒂夫的评论)
使用视图的一个很好的例子是:
scala> (1 to 1000000000).filter(_ % 2 == 0).take(10).toList
java.lang.OutOfMemoryError: GC overhead limit exceeded
在这里 Scala 尝试创建一个包含1000000000
个元素的集合,然后访问前 10 个元素。但是查看:
scala> (1 to 1000000000).view.filter(_ % 2 == 0).take(10).toList
res2: List[Int] = List(2, 4, 6, 8, 10, 12, 14, 16, 18, 20)
我对 Scala 不太了解,但也许这个页面可能会有所帮助......
有两种主要的方法来实现转换器。 一个是严格的,即所有元素的新集合都是由转换器构造的。 另一种是非严格或惰性的,即只为结果集合构造一个代理,并且它的元素仅在需要时才被构造。
视图是一种特殊的集合,代表一些基本集合,但会延迟实现所有转换器。
所以听起来好像代码在没有view
的情况下仍然可以工作,但理论上可能会做一些额外的工作,以严格而不是懒惰的方式构建集合的所有元素。
当您在一个集合上链接多个转换时,我们会创建许多中间 collections 立即丢弃。 例如,在以下代码中:
@ val myArray = Array(1, 2, 3, 4, 5, 6, 7, 8, 9)
@ val myNewArray = myArray.map(x => x + 1).filter(x => x % 2 == 0).slice(1, 3)
myNewArray: Array[Int] = Array(4, 6)
.map
.filter
.slice
操作链最终遍历集合 3 次,创建了三个新的 collections,但只有最后一个集合最终存储在myNewArray
中,其他集合被丢弃。
myArray
1,2,3,4,5,6,7,8,9
map(x => x + 1)
2,3,4,5,6,7,8,9,10
filter(x => x % 2 == 0)
2,4,6,8,10
slice(1, 3)
myNewArray
4,6
这种中间 collections 的创建和遍历是浪费的。 如果您有很长的集合转换链成为性能瓶颈,您可以使用.view
方法和.to
将操作融合在一起:
@ val myNewArray = myArray.view.map(_ + 1).filter(_ % 2 == 0).slice(1, 3).to(Array)
myNewArray: Array[Int] = Array(4, 6)
在map/filter/slice
转换操作之前使用.view
会将新集合的实际遍历和创建推迟到稍后,当我们调用.to
将其转换回具体的集合类型时:
myArray
1,2,3,4,5,6,7,8,9
view map filter slice to
myNewArray
4,6
这允许我们只用一次遍历来执行这个map/filter/slice
转换链,并且只创建一个 output 集合。 这减少了不必要的处理量和 memory 分配。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.