Scala for Backend Engineering & Functional Programming · Lezione

foldLeft e foldRight

Riduca le collezioni a un valore.

Lezione 3 di 413 passaggi

foldLeft e foldRight è una lezione Scala for Backend Engineering & Functional Programming gratuita su CoddyKit. Questa è la lezione 3 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Scala for Backend Engineering & Functional Programming, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Scala for Backend Engineering & Functional Programming include 4 lezioni in totale.

Ridurre una raccolta

La riduzione combina ripetutamente gli elementi con un accumulatore per comprimere una raccolta in un unico valore.

Il modello dell'accumulatore che ha imparato è esattamente ciò che astrae fold. Invece di scrivere personalmente la funzione ausiliaria ricorsiva, fornisce un valore iniziale e una funzione di combinazione.

Nozioni di base su foldLeft

foldLeft accetta un accumulatore iniziale e una funzione (acc, element), quindi percorre la raccolta da sinistra a destra.

A ogni passaggio sostituisce l'accumulatore con il risultato della funzione.

val xs = List(1, 2, 3, 4)
val total = xs.foldLeft(0)((acc, x) => acc + x)

@main def run(): Unit =
  println(total)  // 10

Come associa foldLeft

foldLeft raggruppa da sinistra. Per List(1, 2, 3) con seme z calcola f(f(f(z, 1), 2), 3).

L'accumulatore è l'argomento sinistro, quindi si accumula procedendo verso destra nella lista.

// List(1, 2, 3).foldLeft(0)(_ + _)
// = ((0 + 1) + 2) + 3
// = 6

Nozioni di base su foldRight

foldRight combina anch'esso gli elementi, ma parte da destra.

La sua funzione accetta (element, acc), con l'elemento a sinistra e l'accumulatore a destra.

val xs = List(1, 2, 3, 4)
val total = xs.foldRight(0)((x, acc) => x + acc)

@main def run(): Unit =
  println(total)  // 10

Come associa foldRight

foldRight raggruppa da destra. Per List(1, 2, 3) con seme z calcola f(1, f(2, f(3, z))).

Il seme si trova all'estrema destra e la lista viene combinata procedendo dall'estremità verso l'interno.

// List(1, 2, 3).foldRight(0)(_ + _)
// = 1 + (2 + (3 + 0))
// = 6

Quando la direzione è importante

Per operazioni associative e commutative, come la somma o il prodotto, entrambe le riduzioni producono lo stesso risultato.

Per operazioni non commutative, come la sottrazione o la costruzione di liste, la direzione cambia il risultato. Scelga consapevolmente.

val xs = List(1, 2, 3)
val l = xs.foldLeft(0)(_ - _)   // ((0-1)-2)-3 = -6
val r = xs.foldRight(0)(_ - _)  // 1-(2-(3-0)) = 2

@main def run(): Unit =
  println((l, r))  // (-6, 2)

Costruire una lista

foldRight è la scelta naturale per ricostruire una lista mantenendo l'ordine, perché opera dalla coda verso l'inizio e l'inserimento in testa mantiene gli elementi nella posizione corretta.

In questo modo ogni elemento viene trasformato preservando l'ordine.

val xs = List(1, 2, 3)
val doubled = xs.foldRight(List.empty[Int]) { (x, acc) =>
  (x * 2) :: acc
}

@main def run(): Unit =
  println(doubled)  // List(2, 4, 6)

foldLeft inverte

Se costruisce una lista con foldLeft e inserisce gli elementi in testa, il risultato è invertito, perché gli elementi vengono aggiunti dalla parte anteriore mentre si procede verso destra.

A volte è esattamente il risultato desiderato.

val xs = List(1, 2, 3)
val rev = xs.foldLeft(List.empty[Int]) { (acc, x) =>
  x :: acc
}

@main def run(): Unit =
  println(rev)  // List(3, 2, 1)

Sicurezza dello stack

foldLeft è ricorsivo terminale ed esegue come un ciclo, quindi è sicuro anche su raccolte enormi.

foldRight su una List non è ricorsivo terminale e può causare un overflow dello stack con liste molto lunghe. Preferisca foldLeft quando non è necessario l'ordine da destra a sinistra.

// Safe even for millions of elements:
val n = (1 to 1000000).foldLeft(0L)(_ + _)

// foldRight on a long List risks StackOverflowError

Cambiare il tipo del risultato

Il tipo dell'accumulatore può essere diverso dal tipo degli elementi.

Qui riduciamo una lista di int a una stringa, quindi il seme è una stringa vuota e ogni passaggio concatena un elemento.

Il tipo della riduzione è determinato dal seme.

val xs = List(1, 2, 3)
val s = xs.foldLeft("")((acc, x) => acc + x.toString)

@main def run(): Unit =
  println(s)  // "123"

Fold come coltellino svizzero

Molte operazioni sulle liste sono casi particolari di fold: somma, prodotto, lunghezza, massimo, map, filter, reverse.

Riconoscere la riduzione sottostante aiuta a scrivere codice conciso e dichiarativo invece di ricorrere a una ricorsione scritta manualmente.

val xs = List(4, 1, 7, 3)
val maxV = xs.foldLeft(Int.MinValue)(_ max _)
val len  = xs.foldLeft(0)((acc, _) => acc + 1)

@main def run(): Unit =
  println((maxV, len))  // (7, 4)

Verifica rapida

Ragioni sulla direzione della riduzione e sulla posizione del seme.

Riepilogo

foldLeft procede da sinistra a destra con l'accumulatore a sinistra e calcola ((z op a) op b) op c. È ricorsivo terminale e sicuro per lo stack.

foldRight procede da destra a sinistra con il seme a destra e calcola a op (b op (c op z)). È adatto alla costruzione di liste che preserva l'ordine, ma può causare un overflow con liste lunghe.

Il seme determina il tipo del risultato, quindi le riduzioni possono trasformare una raccolta in qualsiasi valore.

Gratis per iniziare

Impara Scala con un tutor IA — gratis

Scrivi ed esegui vero codice nel tuo browser, ricevi aiuto istantaneo da un tutor IA disponibile 24/7, e riprendi da dove hai lasciato sul web o nell'app.

Corsi
39
Lezioni
143

Domande Frequenti

La lezione «foldLeft e foldRight» è gratuita?

Sì — il testo completo di «foldLeft e foldRight» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Scala for Backend Engineering & Functional Programming, passa a CoddyKit PRO. Il corso Scala for Backend Engineering & Functional Programming include 4 lezioni in totale.

Cosa imparerò in «foldLeft e foldRight»?

Riduca le collezioni a un valore. Eserciti Scala for Backend Engineering & Functional Programming con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare Scala for Backend Engineering & Functional Programming?

Non è richiesta alcuna esperienza precedente. Scala for Backend Engineering & Functional Programming su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 3 di 4.

Quanto tempo richiede la lezione «foldLeft e foldRight»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione Scala for Backend Engineering & Functional Programming?

Sì. Ogni lezione Scala for Backend Engineering & Functional Programming include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Pensare in modo ricorsivo
  2. Pattern dell'accumulatore
  3. foldLeft e foldRight
  4. reduce e aggregate
← Torna a Scala for Backend Engineering & Functional Programming