具体来说,我在这里看问题1
http://pavelfatin.com/scala-for-project-euler/
列出的代码如下
val r = (1 until 1000).view.filter(n => n % 3 == 0 || n % 5 == 0).sum
我可以关注除“视图”之外的所有内容。事实上,如果我拿出视图代码仍然编译并产生完全相同的答案。
答案 0 :(得分:94)
View生成一个惰性集合,以便调用例如filter
不评估集合的每个元素。只有在显式访问元素后才会对元素进行评估。现在sum
可以访问所有元素,但view
对filter
的调用不会创建完整的向量。 (见史蒂夫的评论)
使用视图的一个很好的例子是:
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)
答案 1 :(得分:23)
我对Scala了解不多,但也许this page可能有帮助......
实现变压器有两种主要方式。一个是严格的,这是一个新的集合,其所有元素都是由变压器构成的。另一个是非严格或惰性的,即只构造结果集合的代理,并且只在需要时才构造它的元素。
视图是一种特殊的集合,代表一些基本集合,但是懒洋洋地实现所有变换器。
所以听起来好像代码在没有view
的情况下仍然可以工作,但理论上可能会在 strict 而不是中构建集合中所有元素的额外工作懒惰的时尚。
答案 2 :(得分:1)
当您在一个集合上链接多个转换时,我们正在创建许多中间集合 立即被扔掉。例如,在以下代码中:
@ 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
操作链最终遍历该集合三次,创建了三个
新集合,但只有最后一个集合最终存储在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
创建和遍历中间集合是浪费的。如果您的连锁店很长
集合转换已成为性能瓶颈,您可以使用.view
方法
与.to
一起融合这些操作:
@ val myNewArray = myArray.view.map(_ + 1).filter(_ % 2 == 0).slice(1, 3).to(Array)
myNewArray: Array[Int] = Array(4, 6)
在.view
转换操作之前使用map/filter/slice
会延迟实际遍历,并且
创建新集合,直到稍后调用.to
将其转换回具体的集合类型:
myArray
1,2,3,4,5,6,7,8,9
view map filter slice to
myNewArray
4,6
这使我们可以只进行一次遍历就可以执行此map/filter/slice
转换链,并且
仅创建单个输出集合。这减少了不必要的处理和存储量
分配。