scalaintermediate

Collection Views for Lazy Operations

Use collection views for efficient lazy transformations: avoid intermediate collections and improve performance.

scala
@main def run(): Unit =
  val numbers = (1 to 1_000_000).toList

  // Without view: creates intermediate collections
  val start1 = System.nanoTime()
  val eager = numbers
    .map(_ * 2)
    .filter(_ % 3 == 0)
    .map(_.toString)
    .take(10)
  val eagerTime = (System.nanoTime() - start1) / 1e6
  println(f"Eager: $eagerTime%.2f ms, result: ${eager.take(3)}...")

  // With view: no intermediate collections
  val start2 = System.nanoTime()
  val lazy_ = numbers.view
    .map(_ * 2)
    .filter(_ % 3 == 0)
    .map(_.toString)
    .take(10)
    .toList
  val lazyTime = (System.nanoTime() - start2) / 1e6
  println(f"Lazy:  $lazyTime%.2f ms, result: ${lazy_.take(3)}...")

  // View on Array (no copying)
  val arr = Array.tabulate(1000)(identity)
  val slice = arr.view.slice(100, 200)
  println(s"Slice size: ${slice.size}, first: ${slice.head}")

  // Chained views
  val data = (1 to 100).toVector
  val pipeline = data.view
    .filter(_ % 2 == 0)     // keep evens
    .map(n => n * n)         // square
    .filter(_ < 500)         // under 500
    .map(n => f"val=$n%04d") // format

  // Only materialized when we force
  println(s"Pipeline (lazy, not computed yet): ${pipeline.getClass.getSimpleName}")
  val materialized = pipeline.toList
  println(s"Materialized: $materialized")

  // View for finding first match efficiently
  val largeList = (1 to 10_000_000).toList
  val found = largeList.view
    .map { n =>
      n * n  // expensive computation
    }
    .find(_ > 1_000_000)
  println(s"First square > 1M: $found")  // stops early!

  // GroupBy with view for memory efficiency
  val words = "the quick brown fox jumps over the lazy brown fox".split(" ")
  val grouped = words.view
    .groupBy(identity)
    .map((word, occurrences) => (word, occurrences.length))
    .toMap
  println(s"Word freq: $grouped")

  // View zip (lazy)
  val names = List("Alice", "Bob", "Carol", "Dave")
  val scores = List(95, 87, 92, 88)
  val topScorers = names.view.zip(scores.view)
    .filter(_._2 >= 90)
    .map((name, score) => s"$name: $score")
    .toList
  println(s"Top: $topScorers")

Use Cases

  • Memory-efficient data processing
  • Short-circuit evaluation on large collections
  • Pipeline optimization with lazy evaluation

Tags

Related Snippets

Similar patterns you can reuse in the same workflow.