Iterable.fold în Kotlin

Pornește de la o valoare inițială și o combină pe rând cu fiecare element, întorcând rezultatul final.

Sintaxă
fun <T, R> Iterable<T>.fold(initial: R, operatie: (acc: R, T) -> R): R
fun <T, R> Iterable<T>.foldIndexed(initial: R, operatie: (index: Int, acc: R, T) -> R): R

Ce face Iterable.fold

fold ține o valoare numită de obicei acumulator (acc). Începe cu valoarea initial, apoi pentru fiecare element calculează un acumulator nou din cel vechi și din element. La final întoarce acumulatorul.

Spre deosebire de reduce, fold merge și pe o colecție goală (întoarce initial), iar rezultatul poate avea alt tip decât elementele: poți „strânge” o listă de numere într-un text sau într-un map.

foldIndexed primește în plus poziția elementului, ca prim parametru al lambdei.

Parametri

Parametru Descriere
initial Valoarea de pornire a acumulatorului; este și rezultatul pentru o colecție goală.
operatie Primește acumulatorul curent și elementul (plus indexul la foldIndexed) și întoarce acumulatorul nou.

Ce returnează

Valoarea finală a acumulatorului, de tipul lui initial.

Exemple

Exemplul 1: Soldul unui cont

Pornim de la soldul inițial de 500 de lei și aplicăm fiecare tranzacție (pozitivă = depunere, negativă = plată).

fun main() {
    val tranzactii = listOf(1200, -350, -80, 400, -900)
    val sold = tranzactii.fold(500) { acc, suma -> acc + suma }
    println("Sold final: $sold lei")

    val fara = emptyList<Int>()
    println("Fără tranzacții: ${fara.fold(500) { acc, suma -> acc + suma }} lei")
}

Rezultat

Sold final: 770 lei
Fără tranzacții: 500 lei

Exemplul 2: Rezultat de alt tip decât elementele

Elementele sunt texte, dar acumulatorul este un Int (numărul de vocale). Apoi construim un text pornind de la un text gol.

fun main() {
    val cuvinte = listOf("mere", "pere", "prune")
    val vocale = cuvinte.fold(0) { acc, cuv -> acc + cuv.count { it in "aeiouăâî" } }
    println("Vocale: $vocale")

    val initiale = cuvinte.fold("") { acc, cuv -> acc + cuv.first().uppercaseChar() }
    println("Inițiale: $initiale")
}

Rezultat

Vocale: 6
Inițiale: MPP

Exemplul 3: foldIndexed: puncte după poziție

La un concurs, întrebarea de pe poziția i valorează i + 1 puncte. Adunăm doar punctele răspunsurilor corecte.

fun main() {
    val raspunsuri = listOf(true, false, true, true)
    val puncte = raspunsuri.foldIndexed(0) { i, acc, corect ->
        if (corect) acc + (i + 1) else acc
    }
    println("Punctaj: $puncte din 10")
}

Rezultat

Punctaj: 8 din 10

Greșeli frecvente

  • Inversezi parametrii lambdei: la fold primul este acumulatorul, al doilea elementul. La foldIndexed ordinea este index, acumulator, element.
  • Folosești fold pentru o simplă sumă: sum() sau sumOf sunt mai clare.

Comenzi înrudite

  • Iterable.reduce: Combină elementele pe rând, pornind de la primul element; nu primește valoare inițială.
  • Iterable.runningFold: Ca fold, dar întoarce lista cu toate valorile intermediare ale acumulatorului, de exemplu totalurile parțiale.
  • Iterable.sumOf: Adună valoarea calculată de o funcție pentru fiecare element, de exemplu prețul fiecărui produs din coș.
  • Iterable.joinToString: Lipește elementele într-un singur text, cu separatorul ales, prefix, sufix și, opțional, o transformare.