In Scala, what does "view" do?

Scala

Scala Problem Overview


Specifically I'm looking at Problem 1 here

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

The code as listed is as follows

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

I can follow everything except for "view". In fact if I take out view the code still compiles and produces exactly the same answer.

Scala Solutions


Solution 1 - Scala

View produces a lazy collection, so that calls to e.g. filter do not evaluate every element of the collection. Elements are only evaluated once they are explicitly accessed. Now sum does access all elements, but with view the call to filter doesn't create a full Vector. (See comment by Steve)

A good example of the use of view would be:

scala> (1 to 1000000000).filter(_ % 2 == 0).take(10).toList
java.lang.OutOfMemoryError: GC overhead limit exceeded

Here Scala tries to create a collection with 1000000000 elements to then access the first 10. But with view:

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)

Solution 2 - Scala

I don't know much about Scala, but perhaps this page might help...

>There are two principal ways to implement transformers. One is strict, that is a new collection with all its elements is constructed as a result of the transformer. The other is non-strict or lazy, that is one constructs only a proxy for the result collection, and its elements get constructed only as one demands them. > > A view is a special kind of collection that represents some base collection, but implements all transformers lazily.

So it sounds as if the code will still work without view, but might in theory be doing some extra work constructing all the elements of your collection in strict rather than lazy fashion.

Solution 3 - Scala

The following answer is taken from the Views section in the Hands-on Scala book.

When you chain multiple transformations on a collection, we are creating many intermediate collections that are immediately thrown away. For example, in the following code:

@ 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)

The chain of .map .filter .slice operations ends up traversing the collection three times, creating three new collections, but only the last collection ends up being stored in myNewArray and the others are discarded.

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

This creation and traversal of intermediate collections is wasteful. In cases where you have long chains of collection transformations that are becoming a performance bottleneck, you can use the .view method together with .to to fuse the operations together:

@ val myNewArray = myArray.view.map(_ + 1).filter(_ % 2 == 0).slice(1, 3).to(Array)
myNewArray: Array[Int] = Array(4, 6)

Using .view before the map/filter/slice transformation operations defers the actual traversal and creation of a new collection until later, when we call .to to convert it back into a concrete collection type:

myArray
1,2,3,4,5,6,7,8,9

view map filter slice to

myNewArray
4,6

This allows us to perform this chain of map/filter/slice transformations with only a single traversal, and only creating a single output collection. This reduces the amount of unnecessary processing and memory allocations.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestiondeltanovemberView Question on Stackoverflow
Solution 1 - ScalaKim StebelView Answer on Stackoverflow
Solution 2 - ScalaRichard InglisView Answer on Stackoverflow
Solution 3 - ScalaChemaView Answer on Stackoverflow