C4F: Map, Filter und Reduce kombinieren
Ich kann Map, Filter und Reduce kombiniert verwenden, um Daten zu verarbeiten und zu manipulieren, die komplexere Transformationen erfordern.
Lernziele
| # | Lernziel | Beantwortet in |
|---|---|---|
| 1 | Ich kann filter() und map() kombinieren, um Daten zuerst zu filtern und dann zu transformieren. | 1. Filter + Map Kette |
| 2 | Ich kann map() und reduce() kombinieren, um Daten zu transformieren und anschliessend zu aggregieren. | 2. Map + Reduce Kette |
| 3 | Ich kann filter(), map() und reduce() in einer Pipeline kombinieren, um eine mehrstufige Datenverarbeitung durchzuführen. | 3. Dreifach-Kombination |
1. Filter + Map Kette
Zuerst Elemente auswählen, dann transformieren. Die Reihenfolge ist wichtig: Filtern vor dem Transformieren reduziert die Anzahl der zu verarbeitenden Elemente.
// Nur positive Zahlen quadrieren
var numbers = List.of(1, -2, 3, -4, 5);
var result = numbers.stream()
.filter(x -> x > 0) // [1, 3, 5]
.map(x -> x * x) // [1, 9, 25]
.toList();
System.out.println(result); // [1, 9, 25]
Praxisbeispiel: Produktnamen
record Product(String name, double price) {}
var products = List.of(
new Product("Laptop", 1200.0),
new Product("Maus", 25.0),
new Product("Monitor", 450.0),
new Product("Kabel", 8.0)
);
// Namen aller Produkte über 100 CHF, in Grossbuchstaben
var expensiveNames = products.stream()
.filter(p -> p.price() > 100)
.map(p -> p.name().toUpperCase())
.toList();
System.out.println(expensiveNames); // [LAPTOP, MONITOR]
2. Map + Reduce Kette
Zuerst Daten transformieren, dann zu einem einzelnen Wert zusammenfassen.
// Gesamtpreis aller Produkte berechnen
var total = products.stream()
.map(Product::price) // [1200.0, 25.0, 450.0, 8.0]
.reduce(0.0, Double::sum); // 1683.0
System.out.println(total);
Praxisbeispiel: Zeichenlänge
// Gesamtanzahl Zeichen aller Wörter
var words = List.of("Funktional", "ist", "elegant");
int totalChars = words.stream()
.map(String::length) // [10, 3, 7]
.reduce(0, Integer::sum); // 20
System.out.println(totalChars);
3. Dreifach-Kombination
Die vollständige Pipeline: filtern, transformieren, aggregieren.
// Summe aller verdoppelten Preise über 10 CHF
var prices = List.of(5.0, 15.0, 8.0, 20.0, 3.0, 12.0);
var sum = prices.stream()
.filter(p -> p > 10) // [15.0, 20.0, 12.0]
.map(p -> p * 2) // [30.0, 40.0, 24.0]
.reduce(0.0, Double::sum); // 94.0
System.out.println(sum);
Praxisbeispiel: Lohnsumme
record Employee(String name, String dept, double salary) {}
var employees = List.of(
new Employee("Anna", "IT", 8500),
new Employee("Beat", "IT", 7200),
new Employee("Clara", "HR", 6800),
new Employee("David", "IT", 9100),
new Employee("Eva", "HR", 7000)
);
// Gesamtlohn aller IT-Mitarbeiter mit Gehalt über 8000
var itHighSalary = employees.stream()
.filter(e -> e.dept().equals("IT")) // Anna, Beat, David
.filter(e -> e.salary() > 8000) // Anna, David
.map(Employee::salary) // [8500, 9100]
.reduce(0.0, Double::sum); // 17600.0
System.out.println(itHighSalary);
Vergleich: Imperativ vs. Pipeline
| Aspekt | Imperativ | Stream-Pipeline |
|---|---|---|
| Zwischenvariablen | Mehrere ArrayList-Instanzen | Keine |
| Lesbarkeit | Logik in Schleifen verteilt | Schritte linear von oben nach unten |
| Immutability | Manuell sicherstellen | Automatisch durch Streams |
// Imperativ
var sum = 0.0;
for (var e : employees) {
if (e.dept().equals("IT") && e.salary() > 8000) {
sum += e.salary();
}
}
// Deklarativ (gleiche Logik, klarer strukturiert)
var sum = employees.stream()
.filter(e -> e.dept().equals("IT"))
.filter(e -> e.salary() > 8000)
.map(Employee::salary)
.reduce(0.0, Double::sum);