0Pricing
Scala for Backend Engineering & Functional Programming · Lezione

reduce e aggregate

Scopra altri modi per combinare gli elementi.

reduce e aggregate è una lezione Scala for Backend Engineering & Functional Programming gratuita su CoddyKit. Questa è la lezione 4 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.

Da Fold a Reduce

A volte si desidera combinare gli elementi senza fornire un valore iniziale separato.

reduce usa il primo elemento come accumulatore iniziale e combina al suo interno tutti gli altri.

È una versione più essenziale di fold, adatta ai casi in cui il tipo degli elementi e quello del risultato coincidono.

Nozioni di base su reduce

reduce accetta una funzione binaria (a, b) e la applica alla raccolta, senza un valore iniziale esplicito.

Per una somma, aggiunge semplicemente tutti gli elementi tra loro.

val xs = List(1, 2, 3, 4)
val total = xs.reduce((a, b) => a + b)

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

Il problema delle raccolte vuote

Poiché reduce non ha un seme, chiamarlo su una raccolta vuota genera un'UnsupportedOperationException.

fold e foldLeft sono sicuri sulle raccolte vuote perché usano il seme fornito come valore alternativo.

Scelga reduce solo quando sa che la raccolta non è vuota.

// List.empty[Int].reduce(_ + _)
// throws UnsupportedOperationException

List.empty[Int].foldLeft(0)(_ + _)  // safe, returns 0

reduceOption per maggiore sicurezza

reduceOption restituisce un'Option, fornendo None per una collezione vuota invece di generare un'eccezione.

È il modo sicuro per usare reduce quando la collezione potrebbe essere vuota.

val xs = List(5, 9, 2)
val maybeMax = xs.reduceOption(_ max _)

@main def run(): Unit =
  println(maybeMax)  // Some(9)

reduceLeft e reduceRight

Come fold, anche reduce ha varianti direzionali.

reduceLeft combina da sinistra a destra, mentre reduceRight da destra a sinistra. Un reduce semplice non garantisce l'ordine per le collezioni parallele, quindi usi la variante esplicita quando la direzione è importante.

val xs = List(1, 2, 3)
val l = xs.reduceLeft(_ - _)   // (1-2)-3 = -4
val r = xs.reduceRight(_ - _)  // 1-(2-3) = 2

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

Perché esiste aggregate

fold e reduce richiedono che i tipi dell'accumulatore e degli elementi siano semplicemente correlati.

aggregate è il fold più generale: consente che l'accumulatore sia di un tipo diverso E indica a Scala come unire gli accumulatori parziali, cosa importante per l'elaborazione parallela.

Firma di aggregate

aggregate accetta un valore iniziale, un seqop che inserisce un elemento nell'accumulatore e un combop che unisce due accumulatori.

Su una collezione sequenziale combop viene usato raramente; su una collezione parallela unisce i risultati di ogni blocco.

val xs = List(1, 2, 3, 4)
val sum = xs.aggregate(0)(
  (acc, x) => acc + x,   // seqop
  (a, b)   => a + b      // combop
)

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

aggregate con un tipo diverso

Qui aggregate raccoglie un elenco di parole in un unico totale Int delle lunghezze.

seqop aggiunge la lunghezza di ogni parola, mentre combop somma tra loro due totali parziali.

Il tipo dell'accumulatore (Int) è diverso dal tipo degli elementi (String).

val words = List("hi", "there", "you")
val chars = words.aggregate(0)(
  (acc, w) => acc + w.length,
  (a, b)   => a + b
)

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

Aggregazione parallela

La vera potenza di aggregate emerge con le collezioni parallele.

Ogni thread elabora il proprio blocco con seqop, poi i blocchi vengono uniti con combop. Le due funzioni consentono a Scala di suddividere e ricomporre il lavoro in sicurezza.

// Conceptual: par splits the work
// val n = data.par.aggregate(0)(_ + _.length, _ + _)
// seqop runs per chunk, combop merges chunk results

Scegliere lo strumento giusto

Usi reduce o reduceOption quando il tipo del risultato coincide con quello degli elementi e la combinazione è associativa.

Usi foldLeft quando, in modo sequenziale, serve un valore iniziale o un tipo di risultato diverso.

Usi aggregate quando i tipi dell'accumulatore e degli elementi sono diversi e desidera un'unione adatta all'elaborazione parallela.

// reduce:    same type, non-empty, associative
// foldLeft:  seed + different type, sequential
// aggregate: different type + parallel merge

Combinare in un unico passaggio

aggregate può calcolare più valori contemporaneamente accumulandoli in una tupla.

Qui otteniamo sia la somma sia il conteggio in un unico passaggio, unendo le tuple in combop.

val xs = List(2, 4, 6, 8)
val (s, c) = xs.aggregate((0, 0))(
  (acc, x) => (acc._1 + x, acc._2 + 1),
  (a, b)   => (a._1 + b._1, a._2 + b._2)
)

@main def run(): Unit = println((s, c))  // (20, 4)

Verifica rapida

Decida quale operazione è più sicura per una lista che potrebbe essere vuota.

Riepilogo

reduce combina gli elementi senza un valore iniziale, usando il primo elemento come punto di partenza; genera un'eccezione su una collezione vuota, mentre reduceOption restituisce None.

aggregate è il fold più generale: un valore iniziale, un seqop per raccogliere gli elementi e un combop per unire gli accumulatori parziali nell'elaborazione parallela.

Scelga reduce per combinazioni associative tra valori dello stesso tipo, foldLeft per fold sequenziali con valore iniziale e aggregate quando i tipi sono diversi o si lavora in parallelo.

Domande Frequenti

La lezione «reduce e aggregate» è gratuita?

Sì — il testo completo di «reduce e aggregate» è 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 «reduce e aggregate»?

Scopra altri modi per combinare gli elementi. 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 4 di 4.

Quanto tempo richiede la lezione «reduce e aggregate»?

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