Scala Collections - Stream



Scala Stream is special list with lazy evaluation feature. In scala stream, elements are evaluated only when they are needed. Stream supports lazy computation and is performance savvy.

Declaring Stream Variables

The following is the syntax for declaring an Stream variable.

Syntax

val stream = 1 #:: 2 #:: 3 #:: Stream.empty

Here, stream is declared as a stream of numbers. Here 1 is head of stream, 2, 3 are tail of stream. Stream.empty marks the end of the stream. Values can be retrived using take commands like the following −

Command

stream.take(2)

Processing Stream

Below is an example program of showing how to create, initialize and process Stream −

Example

import scala.collection.immutable.Stream
object Demo {
   def main(args: Array[String]) = {
      val stream = 1 #:: 2 #:: 3 #:: Stream.empty
      // print stream
      println(stream)
      // Print first two elements	
      stream.take(2).print
      println()
      // Create an empty stream
      val stream1: Stream[Int] = Stream.empty[Int]
      // Print element
      println(s"Stream: $stream1")
   }
}

Save the above program in Demo.scala. The following commands are used to compile and execute this program.

Command

\>scalac Demo.scala
\>scala Demo

Output

Stream(1, <not computed>)
1, 2
Stream: Stream()

Creating Infinite Streams

Streams can be used to create infinite sequences. Since they are lazily evaluated, elements are only computed as needed. Here is how you can create an infinite stream:

Example

This example demonstrates how to create an infinite stream using Stream.from and how to take a limited number of elements from it for processing –

object Demo {
   def main(args: Array[String]) = {
      val infiniteStream = Stream.from(1)
      // Take first 5 elements from the infinite stream
      infiniteStream.take(5).print
      println()
   }
}

Save the above program in Demo.scala. Use the following commands to compile and execute this program.

Command

> scalac Demo.scala
> scala Demo

Output

1, 2, 3, 4, 5, empty

Using Stream with Functions

Streams can also be created using functions. This is particularly useful for generating sequences based on a computation.

Example

This example shows how to use a recursive function to generate a Fibonacci sequence as a stream. The function fib generates the sequence, and take is used to retrieve the first 10 elements –

object Demo {
   def main(args: Array[String]) = {
      def fib(a: Int, b: Int): Stream[Int] = a #:: fib(b, a + b)
      val fibStream = fib(1, 1)
      // Take first 10 Fibonacci numbers
      fibStream.take(10).print
      println()
   }
}

Save the above program in Demo.scala. Use the following commands to compile and execute this program.

Command

> scalac Demo.scala
> scala Demo

Output

1, 1, 2, 3, 5, 8, 13, 21, 34, 55, empty

Filtering Stream Elements

You can filter elements of a stream using the filter method, which allows you to create a new stream with only the elements that satisfy a given predicate.

Example

This example demonstrates how to filter a stream to keep only even numbers. The filter method is used to apply the predicate, and the result is printed –

object Demo {
   def main(args: Array[String]) = {
      val stream = 1 #:: 2 #:: 3 #:: 4 #:: 5 #:: Stream.empty
      val evenStream = stream.filter(_ % 2 == 0)
      // Print all even elements
      evenStream.print
      println()
   }
}

Save the above program in Demo.scala. Use the following commands to compile and execute this program.

Command

> scalac Demo.scala
> scala Demo

Output

2, 4, empty

Mapping Stream Elements

The map method allows you to transform each element of a stream using a function.

Example

This example shows how to use the map method to square each element of a stream. The resulting stream of squared values is then printed –

object Demo {
   def main(args: Array[String]) = {
      val stream = 1 #:: 2 #:: 3 #:: 4 #:: Stream.empty
      val squaredStream = stream.map(x => x * x)
      // Print all squared elements
      squaredStream.print
      println()
   }
} 

Save the above program in Demo.scala. Use the following commands to compile and execute this program.

Command

> scalac Demo.scala
> scala Demo

Output

1, 4, 9, 16, empty

Reducing Stream Elements

The reduce method allows you to combine elements of a stream using a binary operation.

Example

This example demonstrates how to use the reduce method to sum all elements of a stream. The sum is then printed –

object Demo {
   def main(args: Array[String]) = {
      val stream = 1 #:: 2 #:: 3 #:: 4 #:: Stream.empty
      val sum = stream.reduce(_ + _)
      // Print the sum of elements
      println(s"Sum: $sum")
   }
}

Save the above program in Demo.scala. Use the following commands to compile and execute this program.

Command

> scalac Demo.scala
> scala Demo

Output

Sum: 10

Scala Streams Summary

  • Streams are special lists that support lazy evaluation.
  • Elements in a stream are only evaluated when needed for performance and efficiency.
  • Streams can be finite or infinite, with infinite streams being generated as needed.
  • Streams can be created using simple declarations or functions.
  • Various operations can be performed on streams, like filtering, mapping, and reducing elements.
  • Streams can handle potentially infinite sequences and support lazy computation. So, these are powerful tools for functional programming in Scala.
Advertisements