scalabeginner

Iterator and Lazy Operations

Use Scala iterators for memory-efficient lazy operations: transform, combine, and consume data streams.

scala
@main def run(): Unit =
  // Basic iterators
  val nums = Iterator(1, 2, 3, 4, 5)
  println(s"Sum: ${nums.sum}")  // consumed!
  // println(nums.sum)  // would be 0, iterator exhausted

  // Iterator from range (lazy)
  val range = Iterator.range(1, 1_000_001)
  val firstSquareOver1M = range.map(n => n * n.toLong).find(_ > 1_000_000)
  println(s"First square > 1M: $firstSquareOver1M")

  // Iterator.iterate
  val powers = Iterator.iterate(1L)(_ * 2).take(20)
  println(s"Powers of 2: ${powers.toList}")

  // Infinite iterator with takeWhile
  val collatz = Iterator.iterate(27) { n =>
    if n % 2 == 0 then n / 2 else 3 * n + 1
  }.takeWhile(_ != 1).toList :+ 1
  println(s"Collatz(27): ${collatz.size} steps")

  // Chained transformations (all lazy)
  val result = Iterator.from(1)
    .map(_ * 3)
    .filter(_ % 2 != 0)
    .drop(5)
    .take(10)
    .toList
  println(s"Filtered: $result")

  // Concatenation
  val combined = Iterator("a", "b") ++ Iterator("c", "d")
  println(s"Combined: ${combined.toList}")

  // Zip
  val names = Iterator("Alice", "Bob", "Carol")
  val scores = Iterator(95, 87, 92)
  val pairs = names.zip(scores).toList
  println(s"Pairs: $pairs")

  // GroupBy-like with sliding
  val data = Iterator.from(1).take(20)
  val batches = data.grouped(5).map(_.toList).toList
  println(s"Batches: $batches")

  // Sliding window
  val windowed = Iterator.from(1).take(10)
    .sliding(3)
    .map(_.toList)
    .toList
  println(s"Windows: $windowed")

  // scanLeft (running accumulator)
  val running = Iterator(1, 2, 3, 4, 5)
    .scanLeft(0)(_ + _)
    .toList
  println(s"Running sum: $running")

  // collect (filter + map)
  val mixed: Iterator[Any] = Iterator(1, "hello", 2, "world", 3)
  val ints = mixed.collect { case i: Int => i * 10 }.toList
  println(s"Collected: $ints")

  // BufferedIterator (peek without consuming)
  val buf = Iterator(1, 2, 3, 4, 5).buffered
  while buf.hasNext && buf.head < 4 do
    print(s"${buf.next()} ")
  println()
  println(s"Remaining head: ${buf.head}")

  // Duplicate iterator
  val (it1, it2) = Iterator(1, 2, 3, 4, 5).duplicate
  println(s"Sum: ${it1.sum}, Max: ${it2.max}")

Use Cases

  • Memory-efficient large data processing
  • Lazy computation chains
  • Streaming data transformations

Tags

Related Snippets

Similar patterns you can reuse in the same workflow.