- scala> Stream.continually("h") zip List(1,2,3,4)
- res2: scala.collection.immutable.Stream[(java.lang.String, Int)] = Stream((h,1), ?)
- scala> res2 mkString ","
- res3: String = (h,1),(h,2),(h,3),(h,4)
- scala> List(1,2,3,4) zip Stream.continually("h")
- res4: List[(Int, java.lang.String)] = List((1,h), (2,h), (3,h), (4,h))
Showing posts with label stream. Show all posts
Showing posts with label stream. Show all posts
Thursday, March 4, 2010
Zip with a constant value
A simple tip for zipping a List (or other collection) with a single value.
Labels:
collections,
Scala,
stream,
zip
Friday, January 22, 2010
Streams 2: Stream construction
This post just adds to the information about streams in the previous post Introducing Streams. In this topic the methods in the Stream object are looked at a little closer:
(standard warning. Examples were done in Scala 2.8 so some examples may need to be modified for Scala 2.7)
(standard warning. Examples were done in Scala 2.8 so some examples may need to be modified for Scala 2.7)
- scala> import Stream._
- import Stream._
- // the empty stream. good for terminating a stream
- scala> empty
- res0: scala.collection.immutable.Stream[Nothing] = Stream()
- // one way to declare a stream.
- scala> 1 #:: 2 #:: empty foreach (println _)
- 1
- 2
- // the other main way to create a stream
- scala> cons(1, cons(2, empty)) foreach println
- 1
- 2
- /*
- Neither of the previous methods of stream creation are particularily useful because they are explicit and therefore they may as well be Lists or some other collection. There is very little benefit in those cases. However when the cons of a stream (tail) is defined as a function then things get a bit more interesting
- */
- scala> def i(x:Int,y:Int):Stream[Int] = (x*y) #:: i(x+1,y*2)
- i: (x: Int,y: Int)Stream[Int]
- scala> i(2,3) take 3 foreach println
- 6
- 18
- 48
- // now lets visit a few more methods in the Stream object
- // create an infinite stream starting at 10
- scala> from (10) take 3 foreach println
- 10
- 11
- 12
- // an infinite stream starting at 10 an increasing by 3
- scala> from (10,3) take 3 foreach println
- 10
- 13
- 16
- // converting an interator to a stream
- scala> (1 until 4).iterator.toStream foreach println
- 1
- 2
- 3
- // creating an Iterable to a stream
- scala> (1 until 4).toStream foreach println
- 1
- 2
- 3
- // a stream that always returns 7
- // the following is a pretty convoluted way to compute 7*49 :-P
- scala> continually(7) take 49 reduceLeft {_ + _}
- res10: Int = 343
- // create a stream of 6 streams
- scala> fill(6)(1 to 2 toStream) foreach println
- Stream(1, ?)
- Stream(1, ?)
- Stream(1, ?)
- Stream(1, ?)
- Stream(1, ?)
- Stream(1, ?)
- /*
- create the same stream as the last example but flatten it out so instead of being a stream of 6 streams it is a stream of 12 elements. Each element in each of the streams are visited in order
- */
- scala> fill(6)(1 to 2 toStream).flatten take 6 foreach println
- 1
- 2
- 1
- 2
- 1
- 2
- /*
- equivalent to:
- (1 until 20 by 3).toStream foreach println
- */
- scala> range(1, 20, 3) foreach println
- 1
- 4
- 7
- 10
- 13
- 16
- 19
- /*
- equivalent to
- (1 until 3).toStream foreach println
- */
- scala> range(1,3) foreach println
- 1
- 2
- /*
- iterate is fun!
- signature is iterator(start)(elem)
- basically starting at 3 execute the function on the previous value in the stream.
- This is an infinite stream
- */
- scala> iterate(3){i => i-10} take 5 foreach println _
- 3
- -7
- -17
- -27
- -37
- /*
- Another example
- */
- scala> iterate(3){i => i*2} take 5 foreach println _
- 3
- 6
- 12
- 24
- 48
- /*
- A final example
- */
- scala> iterate(3){i => i} take 5 foreach println _
- 3
- 3
- 3
- 3
- 3
- /*
- The real final,final example. This example uses the optional length parameter. So the stream is restricted to 5 elements
- */
- scala> iterate(3,5){i => i} foreach println
- 3
- 3
- 3
- 3
- 3
Labels:
intermediate,
Scala,
stream
Monday, January 18, 2010
Introducing Streams
Streams are a special type of Iterable/Traversable whose elements are not evaluated until they are requested. Streams are normally constructed as functions.
A Scala List basically consists of the head element and the rest of the list. A Scala Stream is the head of the stream and a function that can construct the rest of the Stream. It is a bit more than this because each element is evaluated only once and stored in memory for future evaluations. That should be more clear after some examples.
As usual I created these examples with the Scala 2.8 REPL but I think most if not all should work in 2.7.
A very common way to construct a Stream is to define a recursive method. Each recursive call constructs a new element in the stream. The method may or may not have a guard condition that terminates the stream.
This is only an introduction. I hope to add a few more topics that focus on Streams because they can be very powerful but are also more challenging to recognize where they should be used instead of a standard collection.
A Scala List basically consists of the head element and the rest of the list. A Scala Stream is the head of the stream and a function that can construct the rest of the Stream. It is a bit more than this because each element is evaluated only once and stored in memory for future evaluations. That should be more clear after some examples.
As usual I created these examples with the Scala 2.8 REPL but I think most if not all should work in 2.7.
- scala> import Stream.cons
- import Stream.cons
- /*
- Because streams are very functional in nature it is recommended that methods from the Stream object are used for creation
- This is a real boring example of creating a Stream. Anything this simple should be a list.
- The important part is that cons take the value at the point and a function to return the rest of the
- stream NOT another stream.
- */
- scala> val stream1 = cons(0,cons(1,Stream.empty))
- stream1: Stream.Cons[Int] = Stream(0, ?)
- scala> stream1 foreach {print _}
- 01
- /*
- This illustrates the similarity in design between Stream and list, again the difference is the entire list is created in a stream the second argument of cons is not evaluated until it is requested
- */
- scala> new ::(0, new ::(1,List.empty))
- res35: scala.collection.immutable.::[Int] = List(0, 1)
- /*
- To drive home the point of the similarities. Here is an alternative declaration of a
- stream most similar to declaring a list
- */
- scala> val stream2 = 0 #:: 1 #:: Stream.empty
- stream2: scala.collection.immutable.Stream[Int] = Stream(0, ?)
- scala> stream2 foreach {print _}
- 01
- scala> 0 :: 1 :: Nil
- res36: List[Int] = List(0, 1)
- /*
- A little more interesting now. The accessing the second element will run the function. Notice it is not evaluated until request
- */
- scala> val stream3 = cons (0, {
- | println("getting second element")
- | cons(1,Stream.empty)
- | })
- stream3: Stream.Cons[Int] = Stream(0, ?)
- scala> stream3(0)
- res56: Int = 0
- // function is evaluated
- scala> stream3(1)
- getting second element
- res57: Int = 1
- /*
- Function is only evaluated once.
- Important! This means that all elements in a Stream are loaded into a memory so
- it can cause a OutOfMemoryError if the stream is large
- */
- scala> stream3(1)
- res58: Int = 1
- scala> stream3(1)
- res59: Int = 1
- /*
- This creates an infinate stream then forces resolution of all elements
- */
- scala> Stream.from(100).force
- java.lang.OutOfMemoryError: Java heap space
- // Alternative demonstration of laziness
- scala> val stream4 = 0 #:: {println("hi"); 1} #:: Stream.empty
- stream4: scala.collection.immutable.Stream[Int] = Stream(0, ?)
- scala> stream4(1)
- hi
- res2: Int = 1
A very common way to construct a Stream is to define a recursive method. Each recursive call constructs a new element in the stream. The method may or may not have a guard condition that terminates the stream.
- // construct a stream of random elements
- scala> def make : Stream[Int] = Stream.cons(util.Random.nextInt(10), make)
- make: Stream[Int]
- scala> val infinate = make
- infinate: Stream[Int] = Stream(3, ?)
- scala> infinate(5)
- res10: Int = 6
- scala> infinate(0)
- res11: Int = 3
- // Once evaluated each element does not change
- scala> infinate(5)
- res13: Int = 6
- // this function makes a stream that does terminate
- scala> def make(i:Int) : Stream[String] = {
- | if(i==0) Stream.empty
- | else Stream.cons(i + 5 toString, make(i-1))
- | }
- make: (i: Int)Stream[String]
- scala> val finite = make(5)
- finite: Stream[String] = Stream(10, ?)
- scala> finite foreach print _
- 109876
- // One last demonstration of making a stream object
- scala> Stream.cons("10", make(2))
- res18: Stream.Cons[String] = Stream(10, ?)
- /*
- This method is dangerous as it forces the entire stream to be evaluated
- */
- scala> res18.size
- res19: Int = 3
This is only an introduction. I hope to add a few more topics that focus on Streams because they can be very powerful but are also more challenging to recognize where they should be used instead of a standard collection.
Labels:
collections,
intermediate,
list,
non-strict,
Scala,
stream
Subscribe to:
Posts (Atom)