0Pricing
Scala for Backend Engineering & Functional Programming · Lezione

Generatori multipli

Iterazione annidata

Generatori multipli è 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.

L'iterazione annidata diventa lineare

Una for-comprehension può contenere diversi generatori. Ognuno è una riga <- che itera su una collection. Insieme producono ogni combinazione possibile: una sorta di ciclo annidato scritto in forma lineare.

object Main {
  def main(args: Array[String]): Unit = {
    val pairs = for {
      x <- List(1, 2)
      y <- List('a', 'b')
    } yield (x, y)
    println(pairs)
  }
}

È un prodotto cartesiano

Due generatori di dimensioni m e n producono m × n risultati, cioè l'intero prodotto cartesiano. Il primo generatore è il ciclo esterno, il secondo quello interno.

object Main {
  def main(args: Array[String]): Unit = {
    val grid = for {
      row <- 1 to 3
      col <- 1 to 3
    } yield s"r$row-c$col"
    println(grid.mkString(", "))
  }
}

Il generatore interno può dipendere da quello esterno

Un generatore successivo può usare i valori associati dai generatori precedenti. Questo non è possibile con un semplice prodotto cartesiano ed è uno dei motivi per cui le for-comprehension sono così flessibili.

object Main {
  def main(args: Array[String]): Unit = {
    val upperTriangle = for {
      i <- 1 to 4
      j <- i to 4
    } yield (i, j)
    println(upperTriangle)
  }
}

Tre o più generatori

Può concatenare tutti i generatori che desidera. Con tre generatori ottiene un ciclo annidato su tre livelli, che produce tuple o valori calcolati.

object Main {
  def main(args: Array[String]): Unit = {
    val triples = for {
      a <- 1 to 2
      b <- 1 to 2
      c <- 1 to 2
    } yield (a, b, c)
    println(triples.size + " combinations")
    triples.foreach(println)
  }
}

Il classico esempio pitagorico

Un uso famoso consiste nel trovare le terne pitagoriche. Iteriamo su tre numeri e conserviamo solo quelli per cui a*a + b*b == c*c, combinando più generatori con una guardia.

object Main {
  def main(args: Array[String]): Unit = {
    val triples = for {
      a <- 1 to 20
      b <- a to 20
      c <- b to 20
      if a * a + b * b == c * c
    } yield (a, b, c)
    triples.foreach(println)
  }
}

Come viene desugared

Più generatori diventano chiamate flatMap annidate con un map finale:

  • xs.flatMap(x => ys.flatMap(y => zs.map(z => ...)))

Ogni generatore aggiuntivo aggiunge un ulteriore livello di annidamento.

object Main {
  def main(args: Array[String]): Unit = {
    val sugar = for {
      x <- List(1, 2)
      y <- List(3, 4)
    } yield x * y
    val desugared = List(1, 2).flatMap(x => List(3, 4).map(y => x * y))
    println(sugar == desugared)
  }
}

Combinare generatori e guardie

Può alternare liberamente generatori e guardie. Una guardia inserita tra due generatori elimina i valori esterni prima ancora che venga eseguito il ciclo interno.

object Main {
  def main(args: Array[String]): Unit = {
    val result = for {
      x <- 1 to 5
      if x % 2 == 1
      y <- 1 to 5
      if y > x
    } yield (x, y)
    println(result)
  }
}

Appiattire collection annidate

Quando ha una collection di collection, due generatori la appiattiscono naturalmente: il primo itera su quella esterna, il secondo su ciascuna collection interna.

object Main {
  def main(args: Array[String]): Unit = {
    val matrix = List(List(1, 2), List(3, 4), List(5, 6))
    val flat = for {
      row <- matrix
      value <- row
    } yield value
    println(flat)
  }
}

Costruire una griglia di stringhe

Più generatori sono ideali per generare output strutturati, come coordinate o una tabella pitagorica.

object Main {
  def main(args: Array[String]): Unit = {
    val table = for {
      i <- 1 to 3
      j <- 1 to 3
    } yield s"$i*$j=${i * j}"
    println(table.grouped(3).map(_.mkString("  ")).mkString("\n"))
  }
}

Combinare collection di dimensioni diverse

I generatori non devono avere necessariamente la stessa lunghezza. Viene prodotta ogni combinazione formata da un elemento di ciascuno.

object Main {
  def main(args: Array[String]): Unit = {
    val sizes = List("S", "M", "L")
    val colors = List("red", "blue")
    val products = for {
      s <- sizes
      c <- colors
    } yield s"$c-$s"
    println(products)
  }
}

L'ordine influisce sulla sequenza di output

Scambiare l'ordine dei generatori mantiene lo stesso insieme di combinazioni, ma ne cambia l'ordine, perché l'ultimo generatore varia più rapidamente.

object Main {
  def main(args: Array[String]): Unit = {
    val ab = for { x <- List(1, 2); y <- List(9, 8) } yield (x, y)
    val ba = for { y <- List(9, 8); x <- List(1, 2) } yield (x, y)
    println(ab)
    println(ba)
  }
}

Verifica rapida

Quante tuple produce for { x <- List(1,2,3); y <- List('a','b') } yield (x, y)?

Riepilogo

Ha imparato a usare più generatori:

  • Ogni riga <- aggiunge un livello di iterazione annidata
  • Insieme producono il prodotto cartesiano
  • I generatori interni possono dipendere dai valori associati da quelli esterni
  • Vengono desugared in flatMap annidati più un map finale
  • L'ordine dei generatori modifica l'ordine dei risultati

Domande Frequenti

La lezione «Generatori multipli» è gratuita?

Sì — il testo completo di «Generatori multipli» è 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 «Generatori multipli»?

Iterazione annidata 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 «Generatori multipli»?

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. Desugaring di for
  2. Filtrare con if
  3. Generatori multipli
  4. Usare Option e Future
← Torna a Scala for Backend Engineering & Functional Programming