1. Grundlegende Methoden zum Filtern von Sammlungen
Filtern ist wie ein Sieb für Gold, nur dass wir statt Nuggets aus einer Sammlung nur die Elemente auswählen, die wir brauchen. Zum Beispiel haben wir eine Liste von Benutzern – wir wollen nur die Volljährigen finden, oder nur Studenten, oder nur die, die Kaffee mögen (also Programmierer). Das Auswählen passender Elemente ist eine superhäufige Aufgabe, die überall vorkommt: von der Arbeit mit Datenbanken bis zur Verarbeitung von Benutzereingaben.
Schauen wir uns verschiedene Wege an, wie man in C# filtern kann. Während wir das lernen, bauen wir unser Lern-Konsolenprogramm weiter aus und fügen Filter hinzu.
Manuelles Filtern mit einer Schleife
Starten wir mit der einfachsten und klassischsten Methode: Filtern mit foreach:
// Beispiel: Es gibt eine Liste von Zahlen, wir wollen nur die geraden auswählen
List<int> zahlen = new List<int> { 1, 2, 3, 4, 5, 6 };
List<int> geradeZahlen = new List<int>();
foreach (int zahl in zahlen)
{
if (zahl % 2 == 0) // wenn die Zahl gerade ist
{
geradeZahlen.Add(zahl);
}
}
Console.WriteLine("Gerade Zahlen:");
foreach (int n in geradeZahlen)
{
Console.WriteLine(n);
}
So ein Weg funktioniert immer, ist leicht zu verstehen, aber nicht der kompakteste und auch nicht der "modernste".
Warum ist manuelles Filtern nicht immer praktisch?
Wenn du eine andere Sammlung hast, ein anderes Filterkriterium, oder gleich mehrere Filter schreiben musst – dann hast du schnell viel ähnlichen Code. Man wünscht sich mehr Kompaktheit, Lesbarkeit und Modularität.
2. Filtern nach komplexen Kriterien
Angenommen, wir haben eine Sammlung von Objekten. Nehmen wir das Beispiel mit Benutzern aus unserer wachsenden App.
public class Benutzer
{
public string Name { get; set; }
public int Alter { get; set; }
public bool IstStudent { get; set; }
}
Wir deklarieren eine Liste von Benutzern:
List<Benutzer> benutzer = new List<Benutzer>
{
new Benutzer { Name = "Anja", Alter = 17, IstStudent = true },
new Benutzer { Name = "Boris", Alter = 21, IstStudent = false },
new Benutzer { Name = "Vika", Alter = 19, IstStudent = true },
new Benutzer { Name = "Gleb", Alter = 25, IstStudent = false }
};
Beispiel 1: Alle Studenten auswählen
List<Benutzer> studenten = new List<Benutzer>();
foreach (Benutzer user in benutzer)
{
if (user.IstStudent)
studenten.Add(user);
}
Console.WriteLine("Liste der Studenten:");
foreach (Benutzer user in studenten)
{
Console.WriteLine($"{user.Name} ({user.Alter})");
}
Beispiel 2: Nur volljährige Studenten auswählen
List<Benutzer> volljaehrige = new List<Benutzer>();
foreach (Benutzer user in benutzer)
{
if (user.Alter >= 18 && user.IstStudent)
volljaehrige.Add(user);
}
Console.WriteLine("Volljährige Studenten:");
foreach (Benutzer user in volljaehrige)
{
Console.WriteLine($"{user.Name} ({user.Alter})");
}
Und wenn die Filterkriterien dynamisch sind?
Man kann die Filterbedingungen in eigene Methoden auslagern und sie dann in der Schleife aufrufen:
bool IstVolljaehrig(Benutzer u) { return u.Alter >= 18; }
bool IstStudent(Benutzer u) { return u.IstStudent; }
List<Benutzer> gefiltert = new List<Benutzer>();
foreach (Benutzer user in benutzer)
{
if (IstVolljaehrig(user) && IstStudent(user))
gefiltert.Add(user);
}
3. Filtern nach Schlüssel in Dictionaries
Listen und Arrays sind praktisch, aber oft arbeiten wir auch mit Dictionaries.
Angenommen, wir haben ein Dictionary, wo der Schlüssel der Name des Benutzers ist und der Wert sein Alter:
Dictionary<string, int> alterNachName = new Dictionary<string, int>
{
["Anja"] = 17,
["Boris"] = 21,
["Vika"] = 19,
["Gleb"] = 25
};
Aufgabe: Nur Benutzer 18+ auswählen
Dictionary<string, int> volljaehrige = new Dictionary<string, int>();
foreach (var pair in alterNachName)
{
if (pair.Value >= 18)
volljaehrige.Add(pair.Key, pair.Value);
}
Console.WriteLine("Volljährige:");
foreach (var pair in volljaehrige)
{
Console.WriteLine($"{pair.Key}: {pair.Value} Jahre");
}
Aufgabe: Benutzer mit Namen, die mit "V" anfangen, auswählen
Dictionary<string, int> namenMitV = new Dictionary<string, int>();
foreach (var pair in alterNachName)
{
if (pair.Key.StartsWith("V"))
namenMitV.Add(pair.Key, pair.Value);
}
Console.WriteLine("Namen mit 'V':");
foreach (var pair in namenMitV)
{
Console.WriteLine($"{pair.Key}: {pair.Value} Jahre");
}
4. Prinzipien des Filterns
Wie läuft der Filterprozess ab
┌──────────────────────────────────┐
│ Liste: [1, 2, 3, 4, 5, 6] │
└──────────────────────────────────┘
│
▼
[Prüfung: n % 2 == 0]
│
▼
┌──────────────────────────────────┐
│ Ergebnis: [2, 4, 6] │
└──────────────────────────────────┘
Filter kombinieren: Nach verschiedenen Bedingungen filtern
Man kann auch nacheinander filtern, wenn man die Daten schrittweise auswählen will:
// Erstmal nur Studenten filtern
List<Benutzer> nurStudenten = new List<Benutzer>();
foreach (Benutzer user in benutzer)
{
if (user.IstStudent)
nurStudenten.Add(user);
}
// Dann unter ihnen nur die Volljährigen auswählen
List<Benutzer> volljaehrigeStudenten = new List<Benutzer>();
foreach (Benutzer user in nurStudenten)
{
if (user.Alter >= 18)
volljaehrigeStudenten.Add(user);
}
Oder alles auf einmal:
List<Benutzer> volljaehrigeStudenten = new List<Benutzer>();
foreach (Benutzer user in benutzer)
{
if (user.IstStudent && user.Alter >= 18)
volljaehrigeStudenten.Add(user);
}
Sortieren und andere Operationen
Sortieren kann man mit der Sort-Methode für Listen:
// Volljährige Studenten, sortiert nach Alter
volljaehrigeStudenten.Sort((a, b) => a.Alter.CompareTo(b.Alter));
Mehr zum Sortieren gibt's in der nächsten Vorlesung!
5. Filtern in Benutzerszenarien
1. Filtern von Benutzereingaben
Angenommen, unsere App nimmt eine Liste von Noten entgegen und soll alle "Fünfer" auswählen.
Console.Write("Gib die Noten mit Leerzeichen ein: ");
string eingabe = Console.ReadLine();
List<int> noten = new List<int>();
foreach (string s in eingabe.Split(' '))
{
if (int.TryParse(s, out int note))
noten.Add(note);
}
List<int> fuenfer = new List<int>();
foreach (int note in noten)
{
if (note == 5)
fuenfer.Add(note);
}
Console.WriteLine("Fünfer:");
foreach (var note in fuenfer)
{
Console.WriteLine(note);
}
2. Filtern nach mehreren Bedingungen
Aufgabe: Wähle Benutzer-Studenten im Alter von 18 bis einschließlich 22 Jahren aus.
List<Benutzer> gefiltert = new List<Benutzer>();
foreach (Benutzer user in benutzer)
{
if (user.IstStudent && user.Alter >= 18 && user.Alter <= 22)
gefiltert.Add(user);
}
3. Filtern nach Vorhandensein eines Elements
Angenommen, wir haben eine Liste von Strings und wollen nur die auswählen, die die Teilzeichenkette ".net" enthalten (ohne Beachtung der Groß-/Kleinschreibung).
List<string> technologien = new List<string> { "C#", ".NET", "Java", "dotnet", "JavaScript" };
List<string> netTechs = new List<string>();
foreach (var tech in technologien)
{
if (tech.ToLower().Contains(".net"))
netTechs.Add(tech);
}
foreach (var tech in netTechs)
{
Console.WriteLine(tech);
}
6. Besonderheiten und typische Fehler beim Filtern
Filtern wirkt einfach, aber hier kann man einiges falsch machen. Lass uns ein paar Besonderheiten anschauen.
Ändern der Ausgangssammlung
Wenn du die Ausgangssammlung filterst und dann nach dem Filtern ihren Inhalt änderst, – das Ergebnis bleibt gleich, wenn du schon eine neue Liste erstellt hast. Wenn du aber nur die Referenz auf die alte Liste gemerkt hast, können Änderungen an der Ausgangssammlung das Ergebnis beeinflussen.
List<int> gefiltert = new List<int>();
foreach (int n in zahlen)
{
if (n > 2)
gefiltert.Add(n);
}
// Wir ändern die Ursprungsliste
zahlen.Add(10);
foreach (var n in gefiltert)
{
Console.WriteLine(n); // 10 kommt hier nicht rein
}
Ergebnis des manuellen Filterns
Das Ergebnis vom manuellen Filtern ist meistens eine neue veränderbare Liste (zum Beispiel List<T>), mit der du alles machen kannst – Elemente hinzufügen, löschen usw.
Filtern und Performance
Filter in Schleifen werden für jedes Element der Sammlung aufgerufen, also wenn die Funktion im Filter schwer ist – Vorsicht! Manchmal ist eine einfache foreach-Schleife besser, besonders wenn du komplexe Logik, Logging oder zusätzliche Aktionen brauchst.
GO TO FULL VERSION