Menu

C# List: Add, Remove, Contains, Find und Sort

List<T> ist das wachsende Array von C#. Lerne, wie du eine Liste erzeugst, Elemente hinzufügst und einfügst, nach Wert, Index oder Bedingung entfernst, mit Contains und Find suchst, nach einer Property sortierst und den Fehler vermeidest, der beim Ändern einer Liste in foreach entsteht.

Diese Seite enthält ausführbare Editoren - bearbeiten, ausführen und Ausgabe sofort sehen.

List<T> ist eine geordnete Collection, die wächst und schrumpft, wenn du Elemente hinzufügst und entfernst. Sie liegt in System.Collections.Generic, wird wie ein Array indiziert (list[0]) und ist in C# die Standardwahl für „ein paar Dinge“.

Eine Liste erzeugen und Elemente hinzufügen

Der Typparameter in spitzen Klammern sagt, was die Liste enthält: List<string>, List<int>, List<Order>.

Ausgabe:

2
Zoe, Ana, Ben, Chloe, Dev
Ana
Ana B.
3

Count ist eine Property, keine Methode (Arrays verwenden Length, LINQ hat eine Methode Count(); bei einer Liste nimm die Property). Insert schiebt jedes spätere Element eine Position weiter, Einfügen am Anfang einer großen Liste kostet also Zeit proportional zu ihrer Größe. Add am Ende ist die günstige Operation.

Elemente entfernen

Es gibt vier Wege zu entfernen, je nachdem, was du über das Element weißt:

Ausgabe:

True: 85, 62, 40, 91, 55
False
62, 40, 91, 55
2 removed: 62, 91
Caught ArgumentOutOfRangeException
0

Remove nimmt einen Wert und löscht nur den ersten Treffer. Um alle Kopien eines Werts zu löschen, nimm RemoveAll(s => s == 40). Ein ungültiger Index wirft bei einer Liste ArgumentOutOfRangeException (ein Array wirft stattdessen IndexOutOfRangeException), sowohl bei list[i] als auch bei RemoveAt(i). RemoveRange(index, count) entfernt einen Block.

Count gegenüber Capacity

Eine Liste hält ihre Elemente in einem internen Array. Capacity ist die Größe dieses Arrays; Count ist die Anzahl der belegten Plätze. Erreicht Count den Wert Capacity, allokiert das nächste Add ein doppelt so großes Array und kopiert alles hinüber.

Ausgabe:

Count 0, Capacity 0
Count 1, Capacity 4
Count 2, Capacity 4
Count 3, Capacity 4
Count 4, Capacity 4
Count 5, Capacity 8
Count 6, Capacity 8
Count 7, Capacity 8
Count 8, Capacity 8
Count 9, Capacity 16
Count 0, Capacity 1000

Durch das Verdoppeln ist die meisten Add-Aufrufe nur ein Schreiben in einen freien Platz. Wenn du ungefähr weißt, wie viele Elemente kommen, übergib die Zahl an den Konstruktor, um die Zwischenkopien zu sparen. Beachte, dass new List<int>(1000) trotzdem Count 0 hat: list[0] wirft darauf. Kapazität ist Platz, keine Elemente.

Suchen: Contains, IndexOf, Find, Exists

Ausgabe:

True
2
-1
32.00
2 cheap items
False
2
True
False

Find gibt den ersten Treffer zurück oder den Standardwert des Typs (null bei einer Klasse), wenn nichts passt, prüfe also vor der Verwendung des Ergebnisses. Die letzte Zeile gibt False aus, weil Contains Equals verwendet, und eine Klasse ohne überschriebenes Equals vergleicht Referenzen: Ein neues Product mit denselben Feldern ist ein anderes Objekt. Suche stattdessen mit Exists oder Find nach einer Property, oder überschreibe Equals und GetHashCode in der Klasse.

Jede dieser Methoden durchläuft die Liste von Anfang an, jeder Aufruf ist also O(n). Für wiederholte Nachschlagevorgänge über einen Schlüssel antwortet ein Dictionary in konstanter Zeit.

Eine Liste sortieren

Sort() sortiert an Ort und Stelle nach der natürlichen Ordnung der Elemente. Übergib ein Vergleichs-Lambda, um nach etwas anderem zu sortieren.

Ausgabe:

1, 2, 5, 9
9, 5, 2, 1
Ben 95, Ana 120, Chloe 150
Chloe 150, Ben 95, Ana 120
Ben 95, Ana 120, Chloe 150

Ein Vergleich gibt eine negative Zahl zurück, wenn a zuerst kommen soll, eine positive, wenn b zuerst kommen soll, und null bei Gleichstand; CompareTo liefert genau das. Zwei Unterschiede zwischen Sort und OrderBy aus LINQ zählen in der Praxis:

  • Sort ändert die Liste; OrderBy gibt eine neue Sequenz zurück und lässt die Liste in Ruhe.
  • Sort ist nicht stabil: Elemente, die als gleich gelten, können die Plätze tauschen. OrderBy ist stabil, und ThenBy fügt einen zweiten Schlüssel hinzu: players.OrderBy(p => p.Score).ThenBy(p => p.Name).

Sort() auf einer Liste deiner eigenen Klasse ohne Vergleich aufzurufen wirft InvalidOperationException, weil die Liste nicht weiß, wie sie die Elemente ordnen soll. Übergib entweder einen Vergleich oder implementiere IComparable<T> in der Klasse.

Reverse() kehrt an Ort und Stelle um. Weil System.Linq ebenfalls eine Erweiterung Reverse definiert, wählt list.Reverse() auf einer List<T> die Version an Ort und Stelle, die nichts zurückgibt.

Durchlaufen und Entfernen beim Iterieren

foreach liest jedes Element der Reihe nach. Eine for-Schleife gibt dir zusätzlich den Index. Was du nicht tun kannst, ist mitten in einem foreach über dieselbe Liste Elemente hinzuzufügen oder zu entfernen:

Ausgabe:

Caught InvalidOperationException
120, 80, 60
120, 80, 60

Die Exception ist eine InvalidOperationException mit der Meldung „Collection was modified; enumeration operation may not execute.“ Eine vorwärts laufende for-Schleife wirft nicht, überspringt aber stillschweigend das Element direkt nach jedem entfernten, weil alles um einen Index nach vorn rückt. Rückwärts zu laufen vermeidet das. Eine dritte Lösung ist, über eine Kopie zu iterieren: foreach (var t in orders.ToList()).

Eine Property eines Elements in foreach zu ändern (zum Beispiel order.Status = "sent") ist in Ordnung. Hinzufügen oder Entfernen macht den Enumerator kaputt, ebenso das Ersetzen eines Elements über den Indexer (orders[i] = 0).

Zwischen Listen und Arrays umwandeln

Ausgabe:

4
3
4, 4, 4, 4
Oslo / Lima / Pune / Kyiv

Beide Richtungen kopieren die Elemente in neuen Speicher, eine spätere Änderung der Liste wirkt sich also nicht auf das Array aus. ConvertAll ist die eigene Version der Liste von Select(...).ToList() aus LINQ. Eine Liste mit Console.WriteLine(list) auszugeben zeigt den Typnamen (System.Collections.Generic.List`1[System.String]); nimm string.Join.

Kurzübersicht

AufgabeCode
Erzeugenvar l = new List<int>(); oder new List<int> { 1, 2 }
Am Ende hinzufügenl.Add(x), l.AddRange(items)
An einer Position einfügenl.Insert(i, x)
Ersten Treffer entfernenl.Remove(x) (gibt bool zurück)
Nach Index entfernenl.RemoveAt(i)
Nach Bedingung entfernenl.RemoveAll(x => ...) (gibt Anzahl zurück)
Anzahl der Elementel.Count
Enthältl.Contains(x), l.Exists(x => ...)
Findenl.Find(...), l.FindAll(...), l.FindIndex(...)
An Ort und Stelle sortierenl.Sort(), l.Sort((a, b) => ...)
Sortierte Kopiel.OrderBy(x => ...).ToList()
In Arrayl.ToArray()

Häufige Fehler

  • In foreach entfernen. Wirft InvalidOperationException; nimm RemoveAll oder eine rückwärts laufende for-Schleife.
  • Erwarten, dass Remove(x) jede Kopie entfernt. Es entfernt die erste; nimm RemoveAll.
  • Contains auf Objekten ohne Equals verwenden. Es vergleicht Referenzen; suche mit Exists nach einer Property.
  • In eine mit Kapazität erzeugte Liste indizieren. new List<int>(10) ist leer; füge zuerst Elemente hinzu.
  • Annehmen, dass Sort Gleichstände in der Reihenfolge lässt. Tut es nicht; nimm OrderBy, wenn die Reihenfolge unter Gleichen zählt.
  • Eine Liste zuweisen, um sie zu teilen, und dann von Änderungen überrascht sein. var copy = list; ist dieselbe Liste; new List<T>(list) ist eine Kopie.

Häufig gestellte Fragen

Wie füge ich in C# Elemente zu einer List hinzu?

list.Add(item) hängt ein Element ans Ende, list.AddRange(otherCollection) hängt viele an, und list.Insert(index, item) setzt ein Element an eine Position und schiebt den Rest weiter. Du kannst eine Liste auch beim Erzeugen füllen: var names = new List<string> { "Ana", "Ben" };.

Wie entferne ich in C# ein Element aus einer List?

Remove(value) entfernt das erste passende Element und gibt true zurück, wenn es eines gefunden hat. RemoveAt(index) entfernt nach Position. RemoveAll(x => condition) entfernt jedes passende Element und gibt zurück, wie viele es entfernt hat. Clear() leert die Liste.

Wie prüfe ich in C#, ob eine List einen Wert enthält?

list.Contains(value) gibt true oder false zurück. Es vergleicht mit Equals, bei deinen eigenen Klassen also Referenzen, außer die Klasse überschreibt Equals. Um nach einer Property zu prüfen, nimm list.Exists(p => p.Name == "Ana") oder list.Any(...) aus LINQ.

Wie sortiere ich in C# eine List nach einer Property?

Übergib Sort einen Vergleich: people.Sort((a, b) => a.Age.CompareTo(b.Age)) sortiert an Ort und Stelle. Vertausche a und b für absteigende Reihenfolge. Oder nimm LINQ, das eine neue sortierte Sequenz zurückgibt und gleiche Elemente in ihrer ursprünglichen Reihenfolge lässt: people.OrderBy(p => p.Age).ToList().

Warum bekomme ich „Collection was modified; enumeration operation may not execute“?

Du hast Elemente hinzugefügt, entfernt oder ersetzt (list[i] = x), während ein foreach über dieselbe Liste lief, und der Enumerator wirft beim nächsten Schritt InvalidOperationException. Nimm list.RemoveAll(condition), durchlaufe die Liste rückwärts mit einer for-Schleife oder iteriere über eine Kopie wie list.ToList().

Was ist der Unterschied zwischen Count und Capacity?

Count ist die Anzahl der Elemente in der Liste. Capacity ist die Größe des internen Arrays, die mindestens Count beträgt. Wenn das Array voll ist, allokiert die Liste ein neues, doppelt so großes und kopiert die Elemente, daher ist Add im Durchschnitt schnell.

Coddy programming languages illustration

Lerne mit Coddy zu programmieren

LOS GEHT'S