generateSequence în Kotlin

Creează o secvență în care fiecare element se calculează din cel anterior; se oprește când funcția întoarce null.

Sintaxă
fun <T : Any> generateSequence(inceput: T?, urmator: (T) -> T?): Sequence<T>
fun <T : Any> generateSequence(urmator: () -> T?): Sequence<T>

Ce face generateSequence

generateSequence(inceput) { anterior -> urmator } pornește de la o valoare și calculează următoarea din cea precedentă. Secvența se termină când funcția întoarce null; dacă nu întoarce niciodată null, secvența este infinită.

O secvență infinită nu este o problemă cât timp iei doar o parte din ea: take(10), first { ... }, takeWhile { ... }. Elementele se calculează doar când sunt cerute.

Varianta fără valoare de început apelează funcția de fiecare dată (de exemplu pentru a citi linii până la sfârșit: generateSequence(::readLine)).

Parametri

Parametru Descriere
inceput Primul element. Dacă este null, secvența este goală.
urmator Funcția care primește elementul anterior și întoarce următorul, sau null pentru oprire.

Ce returnează

O Sequence<T> (posibil infinită).

Exemple

Exemplul 1: Economii lunare cu dobândă

Pornim de la 1000 de lei și fiecare lună adaugă 2%. Secvența este infinită, așa că luăm doar primele 6 valori.

fun main() {
    val sold = generateSequence(1000.0) { it * 1.02 }
    sold.take(6).forEachIndexed { luna, suma ->
        println("Luna $luna: ${"%.2f".format(suma)} lei")
    }
}

Rezultat

Luna 0: 1000.00 lei
Luna 1: 1020.00 lei
Luna 2: 1040.40 lei
Luna 3: 1061.21 lei
Luna 4: 1082.43 lei
Luna 5: 1104.08 lei

Exemplul 2: Secvență care se oprește singură

Înjumătățim până ajungem la 1; după 1 funcția întoarce null și secvența se termină.

fun main() {
    val injumatatiri = generateSequence(100) { if (it > 1) it / 2 else null }
    println(injumatatiri.toList())

    val putere = generateSequence(1) { it * 2 }.first { it > 1000 }
    println("Prima putere a lui 2 peste 1000: $putere")
}

Rezultat

[100, 50, 25, 12, 6, 3, 1]
Prima putere a lui 2 peste 1000: 1024

Exemplul 3: Citirea liniilor până la sfârșit

readlnOrNull întoarce null la sfârșitul intrării, deci secvența se oprește singură.

fun main() {
    val linii = generateSequence { readlnOrNull() }
    val note = linii.map { it.substringAfter(" ").toInt() }.toList()
    println("Note citite: $note, media ${note.average()}")
}

Ce scrie utilizatorul (intrare)

Ana 9
Ion 7
Maria 10

Rezultat

Note citite: [9, 7, 10], media 8.666666666666666

Greșeli frecvente

  • Apelezi toList() sau count() pe o secvență infinită: programul nu se mai termină (sau rămâne fără memorie). Limitează întâi cu take sau takeWhile.
  • Confunzi valoarea de început cu primul element calculat: inceput apare și el în secvență.

Comenzi înrudite

  • sequence: Construiește o secvență dintr-un bloc de cod care dă valori una câte una cu yield; codul se oprește și continuă la cerere.
  • sequenceOf: Creează o secvență: o colecție „leneșă” ale cărei operații se fac element cu element, doar când ceri rezultatul.
  • Iterable.take: take(n) întoarce primele n elemente, iar drop(n) întoarce tot ce rămâne după ce sari peste primele n.
  • Iterable.takeWhile: takeWhile ia elementele de la început cât timp condiția e adevărată; dropWhile le sare și întoarce restul.