Scala - Infinite Streams



You can create and manipulate potentially infinite sequences of elements using Infinite Streams in Scala. Unlike regular sequences, infinite streams are lazy. So, you can compute elements only as needed, and you can work with large and even infinite datasets without running out of memory.

Declaring Infinite Stream Variables

The following is the syntax for declaring an Infinite Stream variable.

Syntax

val stream: Stream[Int] = Stream.from(1)

Here, stream is declared as an Infinite Stream of integers starting from 1. Streams provide various methods to generate and manipulate sequences.

Creating Infinite Streams

You can create infinite streams using the Stream.from method. It generates a stream of consecutive integers starting from a given value.

Example

Try following example for creating infinite stream of integers starting from 1 -

object Demo {
   def main(args: Array[String]) = {
      // Infinite stream of integers starting from 1
      val stream: Stream[Int] = Stream.from(1)
      // First 10 elements of the stream
      println(stream.take(10).mkString(", "))
   }
}

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, 6, 7, 8, 9, 10

Generating Fibonacci Sequence

You can generate infinite sequences using custom functions. For example, you can generate the Fibonacci sequence using streams.

Example

Try following example for generating Fibonacci sequence -

object Demo {
   def main(args: Array[String]) = {
      // Infinite stream of Fibonacci numbers
      val fibs: Stream[Int] = {
         def loop(a: Int, b: Int): Stream[Int] = a #:: loop(b, a + b)
         loop(0, 1)
      }
      // First 10 Fibonacci numbers
      fibs.take(10).foreach(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

0, 1, 1, 2, 3, 5, 8, 13, 21, 34

Filtering Infinite Streams

You can filter elements in an Infinite Stream using the filter() method. This method returns a new stream containing only the elements that satisfy the predicate.

Example

Try following example for filtering only even numbers from infinite stream -

object Demo {
   def main(args: Array[String]) = {
      // Infinite stream of integers starting from 1
      val stream: Stream[Int] = Stream.from(1)
      // Filtering only even numbers from given stream
      val evenStream = stream.filter(_ % 2 == 0)
      // First 10 filtered even numbers
      println(evenStream.take(10).mkString(", "))
   }
}

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, 6, 8, 10, 12, 14, 16, 18, 20

Transforming Infinite Streams

You can transform an Infinite Stream by using a transformation function to each element using the map() method. This method returns a new stream with the transformed elements.

Example

Try following example for square elements of given infinite stream -

object Demo {
   def main(args: Array[String]) = {
      // Infinite stream of integers starting from 1
      val stream: Stream[Int] = Stream.from(1)
      // Squaring each element using map function
      val squaredStream = stream.map(x => x * x)
      // First 10 squared numbers
      println(squaredStream.take(10).mkString(", "))
   }
}

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, 25, 36, 49, 64, 81, 100

Taking Substreams

You can create substreams by taking a given number of elements from an Infinite Stream using the take() method. This is used for working with finite portions of an infinite sequence.

Example

Try following example for taking substream of an infinite stream -

object Demo {
   def main(args: Array[String]) = {
      // Infinite stream of integers starting from 1
      val stream: Stream[Int] = Stream.from(1)
      // Take the first 5 elements of the stream
      val subStream = stream.take(5)
      // Elements of the subStream
      println(subStream.mkString(", "))
   }
}

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

Dropping Elements

You can skip a given number of elements from the beginning of an Infinite Stream using the drop() method. You can discard initial elements and work with the rest of the stream.

Example

Try following example for deleting first 5 numbers from given infinite stream -

object Demo {
   def main(args: Array[String]) = {
      // Infinite stream of integers starting from 1
      val stream: Stream[Int] = Stream.from(1)
      // Dropping the first 5 elements of the stream
      val droppedStream = stream.drop(5)
      // First 5 elements after dropping
      println(droppedStream.take(5).mkString(", "))
   }
}

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

Command

> scalac Demo.scala
> scala Demo

Output

6, 7, 8, 9, 10

Zipping Infinite Streams

You can combine elements from two infinite streams into pairs using the zip() method. This is used for processing pairs of elements from two streams simultaneously.

Example

Try following example for combining two given infinite streams -

object Demo {
   def main(args: Array[String]) = {
      // Two infinite streams of integers
      val stream1: Stream[Int] = Stream.from(1)
      val stream2: Stream[Int] = Stream.from(100)
      // Zip the two streams together
      val zippedStream = stream1.zip(stream2)
      // First 10 pairs from the zipped stream
      println(zippedStream.take(10).mkString(", "))
   }
}

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,100), (2,101), (3,102), (4,103), (5,104), (6,105), (7,106), (8,107), (9,108), (10,109)

Infinite Streams with Constant Values

You can create an infinite stream of constant values using the Stream.continually method. You can generate an infinite stream where each element is produced by repeatedly evaluating a given expression.

Example

Try following example for generating infinite stream of constant value -

object Demo {
   def main(args: Array[String]) = {
      // Infinite stream of the constant value "Scala"
      val constantStream: Stream[String] = Stream.continually("Scala")
      // First 10 elements of the constant stream
      println(constantStream.take(10).mkString(", "))
   }
}

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

Command

> scalac Demo.scala
> scala Demo

Output

Scala, Scala, Scala, Scala, Scala, Scala, Scala, Scala, Scala, Scala

Infinite Streams Summary

  • You can work with potentially infinite sequences of elements using infinite streams in Scala.
  • Streams are lazy. So you can compute elements only as needed.
  • You can create infinite streams using methods like from and custom functions.
  • Infinite streams can be filtered, transformed, zipped, and manipulated using various methods.
  • Streams allow you to work with large or infinite datasets without running out of memory.
Advertisements