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ń
flatMaporaz końcowegomap - 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
- Desugaring for
- Filtrowanie za pomocą if
- Wiele generatorów
- Używanie Option i Future