Lazy List
A LazyList is a lazy, immutable collection that represents a sequence of elements. Elements of a LazyList are computed only when needed, which allows for efficient handling of potentially infinite sequences.
Creating LazyLists
You can create a LazyList using the LazyList companion object.
val lazyList = LazyList(1, 2, 3, 4, 5)
You can also create an infinite LazyList using the LazyList.cons method or the #:: operator.
// Infinite LazyList of natural numbers
def from(n: Int): LazyList[Int] = n #:: from(n + 1)
val naturals = from(1)
Accessing Elements
Head and Tail
- Head: The first element of the LazyList.
- Tail: The rest of the LazyList (which is lazily evaluated).
val lazyList = LazyList(1, 2, 3, 4, 5)
println(lazyList.head) // 1
println(lazyList.tail) // LazyList(<not computed>)
Taking Elements
You can take the first n elements of a LazyList using the take method.
val naturals = from(1)
val firstFive = naturals.take(5)
println(firstFive.toList) // List(1, 2, 3, 4, 5)
Basic Operations on LazyLists
Mapping
The map method transforms each element of the LazyList using a given function.
val lazyList = LazyList(1, 2, 3, 4, 5)
val squaredLazyList = lazyList.map(n => n * n)
println(squaredLazyList.take(5).toList) // List(1, 4, 9, 16, 25)
Filtering
The filter method selects elements of the LazyList that satisfy a predicate.
val lazyList = LazyList(1, 2, 3, 4, 5)
val evenLazyList = lazyList.filter(_ % 2 == 0)
println(evenLazyList.take(2).toList) // List(2, 4)
Reducing
The reduce method combines the elements of the LazyList using a binary operation.
val lazyList = LazyList(1, 2, 3, 4, 5)
val sum = lazyList.reduce(_ + _)
println(sum) // 15
Folding
The fold method combines elements of the LazyList using a binary operation and a starting value.
val lazyList = LazyList(1, 2, 3, 4, 5)
val sum = lazyList.fold(0)(_ + _)
println(sum) // 15
Infinite LazyLists
One of the key advantages of LazyLists is the ability to handle infinite sequences.
val naturals = from(1)
println(naturals.take(10).toList) // List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
You can create more complex infinite sequences.
val fibs: LazyList[Int] = 0 #:: 1 #:: fibs.zip(fibs.tail).map { case (a, b) => a + b }
println(fibs.take(10).toList) // List(0, 1, 1, 2, 3, 5, 8, 13, 21, 34)
Advanced Operations
Lazy Evaluation
LazyLists are lazily evaluated, meaning elements are computed only when accessed.
val lazyList = LazyList(1, 2, 3, 4, 5)
println(lazyList) // LazyList(<not computed>)
println(lazyList.force) // LazyList(1, 2, 3, 4, 5)
Pattern Matching
You can use pattern matching to deconstruct LazyLists.
val lazyList = LazyList(1, 2, 3, 4, 5)
lazyList match {
case LazyList() => println("The LazyList is empty")
case head #:: tail => println(s"The head is $head and the tail is $tail")
}
// Output: The head is 1 and the tail is LazyList(<not computed>)
Conversions
You can convert LazyLists to other collection types, such as lists or arrays.
val lazyList = LazyList(1, 2, 3, 4, 5)
val list = lazyList.toList
println(list) // List(1, 2, 3, 4, 5)
val array = lazyList.toArray
println(array.mkString(", ")) // 1, 2, 3, 4, 5