程式扎記: [Scala 文章收集] How to use the Scala Stream class, a lazy version of List

標籤

2016年7月26日 星期二

[Scala 文章收集] How to use the Scala Stream class, a lazy version of List

Source From Here 
Preface 
This is an excerpt from the Scala Cookbook (partially modified for the internet). This is Recipe 11.6, “How to Use the Scala Stream Class, a Lazy Version of a List” 

Problem 
You want to use a collection that works like a List but invokes its transformer methods (map, filter, etc.) lazily. 

Solution 
A Scala Stream is like a List, except that its elements are computed lazily, in a manner similar to how a view creates a lazy version of a collection. Because Stream elements are computed lazily, a Stream can be long ... infinitely long. Like a view, only the elements that are accessed are computed. Other than this behavior, a Stream behaves similar to a List

Just like a List can be constructed with ::, a Stream can be constructed with the #:: method, using Stream.empty at the end of the expression instead of Nil
scala> val stream = 1 #:: 2 #:: 3 #:: Stream.empty
stream: scala.collection.immutable.Stream[Int] = Stream(1, ?)

The REPL output shows that the stream begins with the number 1 but uses a ? to denote the end of the stream. This is because the end of the stream hasn’t been evaluated yet. For example, given a Stream: 
scala> val stream = (1 to 1000000).toStream
stream: scala.collection.immutable.Stream[Int] = Stream(1, ?)

you can attempt to access the head and tail of the stream. The head is returned immediately: 
scala> stream.head
res0: Int = 1

but the tail isn’t evaluated yet: 
scala> stream.tail
res2: scala.collection.immutable.Stream[Int] = Stream(2, ?)

The ? symbol is the way a lazy collection shows that the end of the collection hasn’t been evaluated yet. As discussed in Recipe 10.24, “Creating a Lazy View on a Collection”, transformer methods are computed lazily, so when transformers are called, you see the familiar ? character that indicates the end of the stream hasn’t been evaluated yet: 
scala> stream.take(3)
res3: scala.collection.immutable.Stream[Int] = Stream(1, ?)

scala> stream.filter( _ < 200 )
res4: scala.collection.immutable.Stream[Int] = Stream(1, ?)

scala> stream.filter( _ > 200 )
res5: scala.collection.immutable.Stream[Int] = Stream(201, ?)

scala> stream.map { _ * 2 }
res6: scala.collection.immutable.Stream[Int] = Stream(2, ?)

However, be careful with methods that aren’t transformers. Calls to the following strict methods are evaluated immediately and can easily cause java.lang.OutOfMemoryError errors: 
- stream.max
- stream.size
- stream.sum

Transformer methods are collection methods that convert a given input collection to a new output collection, based on an algorithm you provide to transform the data. This includes methods like map, filter, and reverse. When using these methods, you’re transforming the input collection to a new output collection. Methods like maxsize, and sum don’t fit that definition, so they attempt to operate on the Stream, and if the Stream requires more memory than you can allocate, you’ll get the java.lang.OutOfMemoryError. Using a Stream gives you a chance to specify a huge list, and begin working with its elements.

沒有留言:

張貼留言

網誌存檔

關於我自己

我的相片
Where there is a will, there is a way!