1. Grundlegende Suchmöglichkeiten in Kollektionen
Oft werden die Wörter „Suche“ und „Filterung“ als Synonyme verstanden, aber beim Programmieren gibt es da schon Unterschiede.
- Filterung – das ist, wenn wir alle Elemente einer Kollektion bekommen wollen, die einer bestimmten Bedingung entsprechen (zum Beispiel alle Zahlen größer als 10).
- Suche – meistens brauchen wir da nur ein Element: das erste passende, ein Element mit bestimmtem Wert oder einfach nur wissen, ob es überhaupt in der Kollektion ist.
Wenn man das mit einer Bibliothek vergleicht: Filterung ist wie alle Bücher zum Thema „Weltraum“ zu sammeln, und Suche ist wie zu fragen: „Habt ihr das Buch ‘Ulysses’?“ oder „Wo steht das erste Buch mit blauem Einband?“.
Alle wichtigen .NET-Kollektionen (Arrays, Listen, Sets, Dictionaries usw.) unterstützen verschiedene Möglichkeiten, Elemente zu suchen oder auf Vorhandensein zu prüfen.
Schauen wir uns die gängigsten Methoden an:
| Kollektion | Vorhandensein prüfen | Index finden | Element finden | Nach Schlüssel suchen |
|---|---|---|---|---|
|
|
|
|
- |
(Array) |
/ |
|
- | - |
|
|
- | - | - |
|
, |
- | - | Hat Indexer |
Manche Methoden gibt’s nur bei bestimmten Typen.
2. Suche in Listen: List<T>
List<T> ist eine der flexibelsten Kollektionen, um Elemente mit beliebigem Zugriff zu speichern. Hier die wichtigsten Suchmethoden:
Vorhandensein prüfen: Contains
Mit dieser Methode findest du raus, ob ein bestimmtes Element in der Liste ist:
List<string> fruits = new List<string> { "Apfel", "Banane", "Kiwi" };
bool hasKiwi = fruits.Contains("Kiwi"); // true
bool hasMango = fruits.Contains("Mango"); // false
Console.WriteLine(hasKiwi); // True
Unter der Haube geht Contains einfach die Kollektion durch und nutzt Equals.
Index suchen: IndexOf
Wenn du wissen willst, wo genau ein Element steht (seine Nummer in der Liste):
int index = fruits.IndexOf("Banane"); // 1 (nullbasiert)
int absentIndex = fruits.IndexOf("Wassermelone"); // -1 (wenn nicht da)
Console.WriteLine(index);
Console.WriteLine(absentIndex);
Erstes passendes Element finden: Find
Du kannst auch nach einer Bedingung suchen, nicht nur nach einem Wert! Dafür gibt’s Find (oder den Index-Kumpel FindIndex):
// Finde die erste Frucht, deren Name länger als 4 Zeichen ist
string longFruit = fruits.Find(fruit => fruit.Length > 4); // "Apfel"
Console.WriteLine(longFruit);
Achtung: Wenn nichts gefunden wird, kommt der Standardwert für den Typ zurück (null bei Referenzen).
Mehrere Elemente finden: FindAll
Wenn du filtern willst (alle passenden), nimm FindAll:
// Alle Früchte, deren Name den Buchstaben 'i' enthält
List<string> withI = fruits.FindAll(f => f.Contains('i'));
foreach (var fruit in withI)
Console.WriteLine(fruit); // "Kiwi"
3. Suche in Arrays: Methoden der Klasse Array
Arrays haben keine Find-Methode wie List<T>, aber dafür gibt’s die statische Klasse Array:
int[] numbers = { 1, 2, 3, 2, 4 };
int pos = Array.IndexOf(numbers, 2); // 1 — erster Index der 2
int lastPos = Array.LastIndexOf(numbers, 2); // 3 — letzter Index
Console.WriteLine(pos + ", " + lastPos);
Wenn du nach einer Bedingung suchen willst, geht das easy mit einer Schleife:
int firstGreaterThanTwo = -1;
for (int i = 0; i < numbers.Length; i++)
{
if (numbers[i] > 2)
{
firstGreaterThanTwo = numbers[i];
break;
}
}
Console.WriteLine(firstGreaterThanTwo); // 3
4. Universelle Methoden für alle Kollektionen
Viele Kollektionen bieten Suchmethoden (Contains, IndexOf, Find usw.). Wenn du was Komplexeres brauchst, schreibst du einfach eine Schleife.
Beispiel: Prüfen, ob es eine Frucht gibt, die mit "B" anfängt
bool hasB = false;
foreach (var f in fruits)
{
if (f.StartsWith("B"))
{
hasB = true;
break;
}
}
Console.WriteLine(hasB); // True
Beispiel: Erste Frucht finden, die "i" enthält
string withI = null;
foreach (var f in fruits)
{
if (f.Contains('i'))
{
withI = f;
break;
}
}
Console.WriteLine(withI); // "Kiwi"
Beispiel: Suche nach eigenen Objekten
class Student
{
public string Name;
public int Group;
public int Id;
}
List<Student> students = new List<Student>
{
new Student { Name = "Ivan", Group = 101, Id = 1 },
new Student { Name = "Maria", Group = 101, Id = 2 },
new Student { Name = "Pjotr", Group = 102, Id = 3 },
};
// Suche Student mit Id == 2
Student maria = null;
foreach (var s in students)
{
if (s.Id == 2)
{
maria = s;
break;
}
}
if (maria != null)
Console.WriteLine(maria.Name); // "Maria"
else
Console.WriteLine("Student nicht gefunden");
5. Suche in HashSet<T>: nur „Gibt’s das oder nicht?“
Sets (HashSet<T>) sind gemacht für schnelle „Gibt’s das?“-Abfragen. Sie bieten keine Suche nach Index, aber prüfen das Vorhandensein super schnell:
HashSet<int> set = new HashSet<int> { 1, 3, 5, 7 };
bool hasThree = set.Contains(3); // True
Console.WriteLine(hasThree);
// Wenn du nach einer Bedingung suchen willst (z.B. gibt’s gerade Zahlen?):
bool hasEven = false;
foreach (var x in set)
{
if (x % 2 == 0)
{
hasEven = true;
break;
}
}
Console.WriteLine(hasEven); // False
6. Suche in Dictionaries: Dictionary<TKey, TValue>
Ein Dictionary ist eine Kollektion von „Schlüssel-Wert“-Paaren. Die Suche nach dem Schlüssel ist seine Superkraft.
Vorhandensein eines Schlüssels prüfen
Dictionary<int, string> idToName = new Dictionary<int, string>
{
{ 1, "Vasya" }, { 2, "Katja" }
};
if (idToName.ContainsKey(2))
Console.WriteLine(idToName[2]); // "Katja"
Wert nach Schlüssel suchen: sicher!
if (idToName.TryGetValue(3, out string result))
Console.WriteLine(result);
else
Console.WriteLine("Kein Student mit dieser Id"); // Das wird ausgegeben
Suche nach Wert (selten und langsam):
bool containsVasya = idToName.ContainsValue("Vasya");
Console.WriteLine(containsVasya); // True
Eintrag nach Bedingung auf Wert oder Schlüssel finden
// Erster Id, wo der Name mit "K" anfängt
KeyValuePair<int, string> entry = default;
bool found = false;
foreach (var pair in idToName)
{
if (pair.Value.StartsWith("K"))
{
entry = pair;
found = true;
break;
}
}
if (found)
Console.WriteLine($"{entry.Key}: {entry.Value}"); // "2: Katja"
7. Nützliche Details
Tabelle der Suchmethoden
| Kollektionstyp | Vorhandensein prüfen Contains | Index finden IndexOf | Nach Bedingung suchen Find | Sichere Suche nach Schlüssel TryGetValue |
|---|---|---|---|---|
|
Ja | Ja | Ja () |
- |
(Array) |
Ja (/Schleife) |
Ja () |
Schleife | - |
|
Ja | - | Nein (nur manuell) | - |
|
Ja () |
- | Manuell nach Schlüssel/Wert | Ja |
Iterative Suche: selbst schreiben
Für das volle Verständnis schreiben wir mal selbst eine Suchmethode für eine Kollektion. Zum Beispiel: Finde den Index des ersten Elements, das größer als ein bestimmter Wert ist:
static int FindFirstGreaterIndex(IEnumerable<int> collection, int minValue)
{
int index = 0;
foreach (var item in collection)
{
if (item > minValue)
return index;
index++;
}
return -1; // nicht gefunden
}
var nums = new List<int> { 1, 4, 7, 2 };
Console.WriteLine(FindFirstGreaterIndex(nums, 3)); // 1 (Zahl 4)
Hier sind wir nicht an einen Typ gebunden (List<T>, int[], sogar HashSet<T>), und auch nicht an die interne Umsetzung.
Suche in echten Aufgaben
- Suche nach User per Login oder E-Mail in einer Datenbank.
- Prüfen, ob ein bestimmtes Produkt im Warenkorb ist.
- Schnelle Suche nach Einstellungen per Parametername.
- Prüfen, ob ein bestimmter Schritt schon erledigt wurde (z.B. im Workflow).
- Fehlerposition im Log-Array finden.
Bei fast jedem Vorstellungsgespräch für Mid-Level-Entwickler kommt die Frage: „Wie suchst du Elemente in einer Kollektion? Wie würdest du eine Methode schreiben, die das erste/alle/den Index eines Elements nach Bedingung zurückgibt?“ Also: Suchpraxis ist mega wichtig!
8. Typische Fehler und Besonderheiten bei der Suche
Wichtig: Suchmethoden hängen davon ab, wie Objekte verglichen werden. Wenn du eigene Klassen in eine Liste packst, ist der Standardvergleich ein Referenzvergleich! Damit die Suche „nach Inhalt“ klappt, musst du Equals und GetHashCode überschreiben (mehr dazu in den nächsten Vorlesungen).
Beispiel für ein Problem:
var s1 = new Student { Name = "Egor", Id = 42 };
students.Add(s1);
// Jetzt erstellen wir ein neues Objekt mit gleichem Id und Namen:
var s2 = new Student { Name = "Egor", Id = 42 };
Console.WriteLine(students.Contains(s2)); // False (!)
Der Compiler vergleicht nicht nach Feldern, sondern nach Referenz (das sind verschiedene Objekte).
GO TO FULL VERSION