kotlinintermediate

Sequence Generators with yield

Create lazy sequences with sequence builders, yield, yieldAll, and custom infinite generators.

kotlin
// Fibonacci sequence
val fibonacci: Sequence<Long> = sequence {
    var a = 0L
    var b = 1L
    while (true) {
        yield(a)
        val next = a + b
        a = b
        b = next
    }
}

// Collatz sequence
fun collatz(start: Long): Sequence<Long> = sequence {
    var n = start
    yield(n)
    while (n != 1L) {
        n = if (n % 2 == 0L) n / 2 else 3 * n + 1
        yield(n)
    }
}

// Paginated API simulation
data class Page<T>(val items: List<T>, val hasNext: Boolean, val cursor: Int)

fun fetchPage(cursor: Int, pageSize: Int = 5): Page<String> {
    val totalItems = 23
    val start = cursor
    val end = minOf(start + pageSize, totalItems)
    val items = (start until end).map { "Item-$it" }
    return Page(items, end < totalItems, end)
}

fun allItems(): Sequence<String> = sequence {
    var cursor = 0
    var hasMore = true
    while (hasMore) {
        val page = fetchPage(cursor)
        yieldAll(page.items)
        cursor = page.cursor
        hasMore = page.hasNext
    }
}

// Tree traversal with sequence
data class TreeNode(val value: String, val children: List<TreeNode> = emptyList())

fun TreeNode.depthFirst(): Sequence<TreeNode> = sequence {
    yield(this@depthFirst)
    for (child in children) {
        yieldAll(child.depthFirst())
    }
}

fun TreeNode.breadthFirst(): Sequence<TreeNode> = sequence {
    val queue = ArrayDeque<TreeNode>()
    queue.add(this@breadthFirst)
    while (queue.isNotEmpty()) {
        val node = queue.removeFirst()
        yield(node)
        queue.addAll(node.children)
    }
}

// Permutations
fun <T> permutations(list: List<T>): Sequence<List<T>> = sequence {
    if (list.size <= 1) {
        yield(list)
        return@sequence
    }
    for (i in list.indices) {
        val rest = list.toMutableList().apply { removeAt(i) }
        for (perm in permutations(rest)) {
            yield(listOf(list[i]) + perm)
        }
    }
}

// Custom range generator
fun dateRange(start: Int, endInclusive: Int, step: Int = 1) = sequence {
    var current = start
    while (current <= endInclusive) {
        yield(current)
        current += step
    }
}

fun main() {
    // Fibonacci
    println("Fibonacci (first 10): ${fibonacci.take(10).toList()}")
    println("Fib > 100: ${fibonacci.first { it > 100 }}")

    // Collatz
    val seq = collatz(27)
    println("\nCollatz(27): ${seq.take(10).toList()}... (${collatz(27).count()} steps)")

    // Paginated API
    println("\n--- Paginated ---")
    val items = allItems().toList()
    println("Total items: ${items.size}")
    println("First 5: ${items.take(5)}")
    println("Last 5: ${items.takeLast(5)}")

    // Lazy processing
    println("\n--- Lazy ---")
    val result = allItems()
        .filter { it.endsWith("0") || it.endsWith("5") }
        .take(3)
        .toList()
    println("Filtered: $result")

    // Tree traversal
    val tree = TreeNode("root", listOf(
        TreeNode("A", listOf(TreeNode("A1"), TreeNode("A2"))),
        TreeNode("B", listOf(TreeNode("B1"))),
        TreeNode("C")
    ))
    println("\nDFS: ${tree.depthFirst().map { it.value }.toList()}")
    println("BFS: ${tree.breadthFirst().map { it.value }.toList()}")

    // Permutations (lazy — won't compute all)
    val perms = permutations(listOf(1, 2, 3))
    println("\nPermutations: ${perms.toList()}")

    // Infinite sequence with generateSequence
    val powers = generateSequence(1) { it * 2 }
    println("\nPowers of 2: ${powers.take(10).toList()}")

    // Iterator protocol
    println("\nCustom range: ${dateRange(2020, 2025).toList()}")
}

Use Cases

  • Lazy paginated API consumption
  • Tree and graph traversal
  • Mathematical sequence generation

Tags

Related Snippets

Similar patterns you can reuse in the same workflow.