Streams in Scala: Part 2

Part 1 covered what streams are and gave a few examples that basically treated streams like lists before showing the most common way of creating a stream using a recursive function definition. That post by no means covered enough to actually do streams justice.

The Stream library in Scala is very powerful. I will return to recursive function streams in part 3 but I wanted to make sure that a few basic usages of the library are covered since it gives you practical problem-solving powers that my favorite language, Java, does not possess in such a compact, elegant form.

As you’ll see, most of this applies to lists as well. But as mentioned before, the power of streams over lists is that they are evaluated only when needed rather than generated all at once. Furthermore they are memoized or cached in memory once a value is generated.

From
The from method intuitively gives you an Int stream starting from some start value.


scala> Stream.from(1) take 10 print ", "
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, empty

scala> Stream.from(100) take 15 print ", "
100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, empty

Filter
The filter method, much like it sounds, can be used to take a stream and remove some values, letting others “filter through.” It takes a function that returns a boolean as its parameter. If this function returns true the value is filtered through. In the following example even numbers are generated with the underscore syntax. The underscore serves as a placeholder for an anonymous function parameter. In the odd number example I use a more traditional function syntax to show the equivalent longhand form.


scala> def evens = Stream.from(100) filter(_ % 2 == 0)
evens: scala.collection.immutable.Stream[Int]

scala> evens take 10 print ", "
100, 102, 104, 106, 108, 110, 112, 114, 116, 118, empty

scala> def odds = Stream.from(100) filter( x => x % 2 != 0 )
odds: scala.collection.immutable.Stream[Int]

scala> odds take 10 print ", "
101, 103, 105, 107, 109, 111, 113, 115, 117, 119, empty

Map
Map lets you take each value of the stream and map it through a function to some other value. This is an alternate way to generate series of numbers like the squares I talked about in A Look at Scala Implicit Conversions.


scala> def squares = Stream.from(1) map (x => x * x)
squares: scala.collection.immutable.Stream[Int]

scala> squares take 10 print ", "
1, 4, 9, 16, 25, 36, 49, 64, 81, 100, empty

Here is another way to generate even numbers using map:


scala> Stream.from(1) map(_*2) take 10 print ", "
2, 4, 6, 8, 10, 12, 14, 16, 18, 20, empty

Reduce
Reduce moves along the stream and applies a function that accumulates a value. Therefore it requires a function with two parameters–the accumulating value and the value of the current place in the stream. For example, you can sum the numbers from one to ten like this:


scala> Stream.from(1) take 10 reduce (_+_)
res2: Int = 55

Or you can combine it with other stream functions…say you want to sum those even numbers:

scala> Stream.from(1) map(_*2) take 10 reduce(_+_)
res5: Int = 110

There are also “reduceLeft” and “reduceRight” methods which change how the reduction is performed. See the API for details.

Conclusion
This scratches merely the surface of the surface, but it is good to see some basic functions of the Stream library that you will likely use quite often. In part 3, I will show how to implement the same code that was used in this post comparing Java 7 and Java 8, giving us a comparison of all three.

One thought on “Streams in Scala: Part 2

Leave a Reply

Your email address will not be published. Required fields are marked *