When to Use Sequences

Rules of Thumb

  • Use a List for small collections (hundreds of items) and one or two operations. It is simpler and often faster.
  • Use a Sequence for large collections with several chained operations, when you need only the first few results, or when the data is infinite or generated.
  • Reading a big file line by line: File.useLines { lines -> lines.filter {...}.count() } gives a sequence and never loads the whole file.
  • A sequence can be iterated more than once only if its source allows it; generateSequence(seed) can, but a sequence over an Iterator cannot (use constrainOnce to make that explicit).

Counting the Work

Example

Count how many times map runs when we need only 3 results from 1 million numbers.

fun main() {
    var listOps = 0
    val fromList = (1..1_000_000).toList()
        .map { listOps++; it * 3 }
        .filter { it % 7 == 0 }
        .take(3)

    var seqOps = 0
    val fromSeq = (1..1_000_000).asSequence()
        .map { seqOps++; it * 3 }
        .filter { it % 7 == 0 }
        .take(3)
        .toList()

    println("List result $fromList, map ran $listOps times")
    println("Sequence result $fromSeq, map ran $seqOps times")
}

Output

List result [21, 42, 63], map ran 1000000 times
Sequence result [21, 42, 63], map ran 21 times