在Scala中,“视图”有什么作用?

时间:2011-07-23 09:56:07

标签: scala

具体来说,我在这里看问题1

http://pavelfatin.com/scala-for-project-euler/

列出的代码如下

val r = (1 until 1000).view.filter(n => n % 3 == 0 || n % 5 == 0).sum

我可以关注除“视图”之外的所有内容。事实上,如果我拿出视图代码仍然编译并产生完全相同的答案。

3 个答案:

答案 0 :(得分:94)

View生成一个惰性集合,以便调用例如filter不评估集合的每个元素。只有在显式访问元素后才会对元素进行评估。现在sum可以访问所有元素,但viewfilter的调用不会创建完整的向量。 (见史蒂夫的评论)

使用视图的一个很好的例子是:

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转换链,并且 仅创建单个输出集合。这减少了不必要的处理和存储量 分配。