Scala för backendutveckling och funktionell programmering · Lektion

Flera generatorer

Nästad iteration.

Lektion 3 av 413 steg

Flera generatorer är en gratis lektion i Scala för backendutveckling och funktionell programmering på CoddyKit. Detta är lektion 3 av 4. Ni kan läsa hela lektionen gratis nedan och sedan öva praktiskt i webbläsaren med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt. Den ingår i lärvägen för Scala för backendutveckling och funktionell programmering, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i Scala för backendutveckling och funktionell programmering innehåller totalt 4 lektioner.

Nästad iteration i platt form

En for-comprehension kan ha flera generatorer. Var och en är en <--rad som itererar över en samling. Tillsammans producerar de alla kombinationer – en sorts nästad loop som skrivs i platt form.

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

Det är en kartesisk produkt

Två generatorer med storlekarna m och n producerar m × n resultat, alltså hela den kartesiska produkten. Den första generatorn är den yttre loopen och den andra den inre.

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(", "))
  }
}

Den inre generatorn kan bero på den yttre

En senare generator kan använda värden som bundits av tidigare generatorer. Detta är inte möjligt med en vanlig kartesisk produkt och är en av anledningarna till att for-comprehensions är så flexibla.

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 eller fler generatorer

Du kan stapla så många generatorer du vill. Med tre generatorer får du en loop nästad i tre nivåer, som producerar tupler eller beräknade värden.

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)
  }
}

Det klassiska pytagoreiska exemplet

En berömd användning är att hitta pytagoreiska tripplar. Vi itererar över tre tal och behåller bara dem där a*a + b*b == c*c gäller, genom att kombinera flera generatorer med en guard.

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)
  }
}

Så desugar det

Flera generatorer blir nästlade flatMap-anrop med ett avslutande map:

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

Varje extra generator lägger till ytterligare en nästad nivå.

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)
  }
}

Blanda generatorer och guards

Du kan fritt blanda generatorer och guards. En guard som placeras mellan två generatorer sållar bort yttre värden innan den inre loopen ens körs.

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)
  }
}

Platta ut nästlade samlingar

När du har en samling av samlingar plattar två generatorer naturligt ut den: den första itererar över den yttre samlingen och den andra över varje inre samling.

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)
  }
}

Bygga ett strängrutnät

Flera generatorer passar utmärkt för att generera strukturerade resultat, till exempel koordinater eller en multiplikationstabell.

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"))
  }
}

Kombinera samlingar av olika storlek

Generatorerna behöver inte ha samma längd. Varje kombination av ett element från varje samling produceras.

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)
  }
}

Ordningen påverkar resultatsekvensen

Om du byter ordning på generatorerna får du samma uppsättning kombinationer, men deras ordning ändras eftersom den sista generatorn varierar snabbast.

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)
  }
}

Snabb kontroll

Hur många tupler producerar for { x <- List(1,2,3); y <- List('a','b') } yield (x, y)?

Sammanfattning

Du har lärt dig om flera generatorer:

  • Varje <--rad lägger till en nivå av nästad iteration
  • Tillsammans producerar de den kartesiska produkten
  • Inre generatorer kan bero på yttre bundna värden
  • De desugar till nästlade flatMap samt ett avslutande map
  • Generatorernas ordning ändrar resultatens ordning
Gratis att börja

Lär dig Scala med en AI-lärare – gratis

Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.

Kurser
39
Lektioner
143

Vanliga frågor

Är lektionen ”Flera generatorer” gratis?

Ja – hela texten till ”Flera generatorer” kan läsas gratis här på webben. Om Ni vill öva interaktivt med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt och låsa upp resten av kursen i Scala för backendutveckling och funktionell programmering, kan Ni uppgradera till CoddyKit PRO. Kursen i Scala för backendutveckling och funktionell programmering innehåller totalt 4 lektioner.

Vad lär jag mig i ”Flera generatorer”?

Nästad iteration. Ni övar på Scala för backendutveckling och funktionell programmering med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.

Behöver jag någon erfarenhet för att börja lära mig Scala för backendutveckling och funktionell programmering?

Du behöver inga förkunskaper. Utbildningen i Scala för backendutveckling och funktionell programmering på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 3 av 4.

Hur lång tid tar lektionen ”Flera generatorer”?

De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.

Kan jag skriva och köra kod i den här Scala för backendutveckling och funktionell programmering-lektionen?

Ja. Varje Scala för backendutveckling och funktionell programmering-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.

Alla lektioner i den här kursen

  1. Desugaring av for
  2. Filtrera med if
  3. Flera generatorer
  4. Använda Option och Future
← Tillbaka till Scala för backendutveckling och funktionell programmering