0Pricing
Scala for Backend Engineering & Functional Programming · Lekcja

Wiele generatorów

Zagnieżdżona iteracja

Wiele generatorów to bezpłatna lekcja Scala for Backend Engineering & Functional Programming na CoddyKit. To lekcja 3 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Scala for Backend Engineering & Functional Programming, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Scala for Backend Engineering & Functional Programming zawiera 4 lekcji w sumie.

Zagnieżdżona iteracja spłaszczona

For-comprehension może zawierać kilka generatorów. Każdy z nich to wiersz <-, który iteruje po kolekcji. Razem tworzą każdą kombinację — jest to rodzaj zagnieżdżonej pętli zapisanej płasko.

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

To iloczyn kartezjański

Dwa generatory o rozmiarach m i n tworzą m × n wyników, czyli pełny iloczyn kartezjański. Pierwszy generator jest pętlą zewnętrzną, a drugi — wewnętrzną.

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

Wewnętrzny generator może zależeć od zewnętrznego

Późniejszy generator może używać wartości powiązanych przez wcześniejsze generatory. Nie jest to możliwe przy zwykłym iloczynie kartezjańskim i jest jednym z powodów, dla których for-comprehensions są tak elastyczne.

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

Trzy lub więcej generatorów

Można łączyć dowolną liczbę generatorów. Przy trzech generatorach otrzymuje się potrójnie zagnieżdżoną pętlę, która tworzy krotki lub obliczone wartości.

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

Klasyczny przykład pitagorejski

Słynne zastosowanie: znajdowanie trójek pitagorejskich. Iterujemy po trzech liczbach i zachowujemy tylko te, dla których a*a + b*b == c*c, łącząc wiele generatorów ze strażnikiem.

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

Jak to się rozwija

Wiele generatorów zamienia się w zagnieżdżone wywołania flatMap z końcowym map:

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

Każdy dodatkowy generator dodaje kolejny poziom zagnieżdżenia.

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

Łączenie generatorów i strażników

Generatory i strażniki można dowolnie przeplatać. Strażnik umieszczony między dwoma generatorami odrzuca wartości zewnętrzne, zanim w ogóle uruchomi się pętla wewnętrzna.

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

Spłaszczanie zagnieżdżonych kolekcji

Gdy masz kolekcję kolekcji, dwa generatory naturalnie ją spłaszczają: pierwszy iteruje po kolekcji zewnętrznej, a drugi po każdej kolekcji wewnętrznej.

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

Budowanie siatki napisów

Wiele generatorów świetnie nadaje się do tworzenia uporządkowanych wyników, takich jak współrzędne czy tabliczka mnożenia.

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

Łączenie kolekcji o różnych rozmiarach

Generatory nie muszą mieć tej samej długości. Tworzona jest każda kombinacja po jednym elemencie z każdej kolekcji.

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

Kolejność wpływa na sekwencję wynikową

Zamiana kolejności generatorów zachowuje ten sam zbiór kombinacji, ale zmienia ich kolejność, ponieważ ostatni generator zmienia się najszybciej.

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

Szybkie sprawdzenie

Ile krotek tworzy for { x <- List(1,2,3); y <- List('a','b') } yield (x, y)?

Podsumowanie

Poznałeś(-aś) wiele generatorów:

  • Każdy wiersz <- dodaje poziom zagnieżdżonej iteracji
  • Razem tworzą iloczyn kartezjański
  • Generatory wewnętrzne mogą zależeć od wartości powiązanych przez generatory zewnętrzne
  • Rozwijają się do zagnieżdżonych wywołań flatMap oraz końcowego map
  • Kolejność generatorów zmienia kolejność wyników

Często zadawane pytania

Czy lekcja „Wiele generatorów” jest bezpłatna?

Tak — pełny tekst „Wiele generatorów” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Scala for Backend Engineering & Functional Programming, przejdź na CoddyKit PRO. Kurs Scala for Backend Engineering & Functional Programming zawiera 4 lekcji w sumie.

Co nauczysz się w „Wiele generatorów”?

Zagnieżdżona iteracja Ćwiczysz Scala for Backend Engineering & Functional Programming z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Scala for Backend Engineering & Functional Programming?

Nie wymagamy żadnego doświadczenia. Scala for Backend Engineering & Functional Programming w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 3 z 4.

Ile czasu zajmuje lekcja „Wiele generatorów”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Scala for Backend Engineering & Functional Programming?

Tak. Każda lekcja Scala for Backend Engineering & Functional Programming zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Desugaring for
  2. Filtrowanie za pomocą if
  3. Wiele generatorów
  4. Używanie Option i Future
← Powrót do Scala for Backend Engineering & Functional Programming