Menu

List en C# : Add, Remove, Contains, Find et Sort

List<T> est le tableau extensible de C#. Apprenez à créer une liste, ajouter et insérer des éléments, supprimer par valeur, par index ou par condition, chercher avec Contains et Find, trier par propriété, et éviter l'erreur provoquée par la modification d'une liste dans un foreach.

Cette page contient des éditeurs exécutables - modifiez, exécutez et voyez la sortie instantanément.

List<T> est une collection ordonnée qui grandit et rétrécit au fil des ajouts et des suppressions. Elle se trouve dans System.Collections.Generic, s'indexe comme un tableau (list[0]) et c'est le choix par défaut pour « un ensemble de choses » en C#.

Créer une liste et ajouter des éléments

Le paramètre de type entre chevrons indique ce que contient la liste : List<string>, List<int>, List<Order>.

Sortie :

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

Count est une propriété, pas une méthode (les tableaux utilisent Length, LINQ a une méthode Count() ; sur une liste, utilisez la propriété). Insert décale d'une place chaque élément suivant, donc insérer au début d'une grande liste coûte un temps proportionnel à sa taille. Add à la fin est l'opération peu coûteuse.

Supprimer des éléments

Il existe quatre façons de supprimer, selon ce que vous savez de l'élément :

Sortie :

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

Remove prend une valeur et ne supprime que la première correspondance. Pour supprimer toutes les copies d'une valeur, utilisez RemoveAll(s => s == 40). Un mauvais index sur une liste lève ArgumentOutOfRangeException (un tableau lève IndexOutOfRangeException à la place), aussi bien pour list[i] que pour RemoveAt(i). RemoveRange(index, count) supprime un bloc.

Count ou Capacity

Une liste garde ses éléments dans un tableau interne. Capacity est la taille de ce tableau ; Count est le nombre d'emplacements utilisés. Quand Count atteint Capacity, l'Add suivant alloue un tableau deux fois plus grand et y recopie tout.

Sortie :

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

Le doublement fait que la plupart des appels à Add se réduisent à une écriture dans un emplacement libre. Si vous savez à peu près combien d'éléments arrivent, passez ce nombre au constructeur pour éviter les copies intermédiaires. Notez que new List<int>(1000) a toujours un Count de 0 : list[0] sur cette liste lève une exception. La capacité est de la place, pas des éléments.

Chercher : Contains, IndexOf, Find, Exists

Sortie :

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

Find renvoie la première correspondance, ou la valeur par défaut du type (null pour une classe) quand rien ne correspond, donc vérifiez avant d'utiliser le résultat. La dernière ligne affiche False parce que Contains utilise Equals, et une classe sans redéfinition d'Equals compare des références : un nouveau Product aux mêmes champs est un objet différent. Cherchez plutôt par propriété avec Exists ou Find, ou redéfinissez Equals et GetHashCode dans la classe.

Chacune de ces méthodes parcourt la liste depuis le début, donc chaque appel est en O(n). Pour des recherches répétées par clé, un Dictionary répond en temps constant.

Trier une liste

Sort() trie sur place selon l'ordre naturel des éléments. Passez une lambda de comparaison pour trier selon autre chose.

Sortie :

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

Une comparaison renvoie un nombre négatif quand a doit venir en premier, positif quand c'est b, et zéro en cas d'égalité ; CompareTo produit exactement cela. Deux différences entre Sort et l'OrderBy de LINQ comptent en pratique :

  • Sort modifie la liste ; OrderBy renvoie une nouvelle séquence et laisse la liste intacte.
  • Sort n'est pas stable : des éléments égaux peuvent échanger leurs places. OrderBy est stable, et ThenBy ajoute une seconde clé : players.OrderBy(p => p.Score).ThenBy(p => p.Name).

Appeler Sort() sur une liste de votre propre classe sans comparaison lève InvalidOperationException, car la liste ne sait pas comment ordonner les éléments. Passez une comparaison ou implémentez IComparable<T> dans la classe.

Reverse() inverse sur place. Comme System.Linq définit aussi une extension Reverse, list.Reverse() sur une List<T> choisit la version sur place, qui ne renvoie rien.

Parcourir, et supprimer pendant le parcours

foreach lit chaque élément dans l'ordre. Une boucle for donne aussi l'index. Ce que vous ne pouvez pas faire, c'est ajouter ou supprimer des éléments au milieu d'un foreach sur la même liste :

Sortie :

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

L'exception est une InvalidOperationException avec le message « Collection was modified; enumeration operation may not execute. » Une boucle for vers l'avant ne lève pas d'exception, mais elle saute silencieusement l'élément qui suit chaque suppression, car tout se décale d'un index vers le bas. Parcourir à l'envers évite cela. Une troisième correction consiste à itérer sur une copie : foreach (var t in orders.ToList()).

Modifier une propriété d'un élément dans un foreach (par exemple order.Status = "sent") ne pose pas de problème. Ajouter ou supprimer des éléments casse l'énumérateur, tout comme en remplacer un via l'indexeur (orders[i] = 0).

Convertir entre listes et tableaux

Sortie :

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

Les deux directions copient les éléments dans un nouveau stockage, donc modifier la liste ensuite n'affecte pas le tableau. ConvertAll est la version propre à la liste de Select(...).ToList() de LINQ. Afficher une liste avec Console.WriteLine(list) montre le nom du type (System.Collections.Generic.List`1[System.String]) ; utilisez string.Join.

Référence rapide

TâcheCode
Créervar l = new List<int>(); ou new List<int> { 1, 2 }
Ajouter à la finl.Add(x), l.AddRange(items)
Insérer à une positionl.Insert(i, x)
Supprimer la première correspondancel.Remove(x) (renvoie un bool)
Supprimer par indexl.RemoveAt(i)
Supprimer par conditionl.RemoveAll(x => ...) (renvoie le nombre)
Nombre d'élémentsl.Count
Contientl.Contains(x), l.Exists(x => ...)
Trouverl.Find(...), l.FindAll(...), l.FindIndex(...)
Trier sur placel.Sort(), l.Sort((a, b) => ...)
Copie triéel.OrderBy(x => ...).ToList()
Vers un tableaul.ToArray()

Erreurs courantes

  • Supprimer dans un foreach. Cela lève InvalidOperationException ; utilisez RemoveAll ou une boucle for à l'envers.
  • S'attendre à ce que Remove(x) supprime chaque copie. Il supprime la première ; utilisez RemoveAll.
  • Utiliser Contains sur des objets sans Equals. Cela compare des références ; cherchez par propriété avec Exists.
  • Indexer une liste créée avec une capacité. new List<int>(10) est vide ; ajoutez d'abord des éléments.
  • Supposer que Sort garde l'ordre des égalités. Ce n'est pas le cas ; utilisez OrderBy quand l'ordre entre éléments égaux compte.
  • Affecter une liste pour la partager, puis s'étonner des modifications. var copy = list; est la même liste ; new List<T>(list) est une copie.

Questions fréquentes

Comment ajouter des éléments à une List en C# ?

list.Add(item) ajoute un élément à la fin, list.AddRange(otherCollection) en ajoute plusieurs, et list.Insert(index, item) place un élément à une position en décalant le reste. Vous pouvez aussi remplir une liste à sa création : var names = new List<string> { "Ana", "Ben" };.

Comment supprimer un élément d'une List en C# ?

Remove(value) supprime le premier élément correspondant et renvoie true s'il en a trouvé un. RemoveAt(index) supprime par position. RemoveAll(x => condition) supprime tous les éléments qui correspondent et renvoie leur nombre. Clear() vide la liste.

Comment vérifier qu'une List contient une valeur en C# ?

list.Contains(value) renvoie true ou false. La méthode compare avec Equals, donc pour vos propres classes elle compare des références, sauf si la classe redéfinit Equals. Pour vérifier selon une propriété, utilisez list.Exists(p => p.Name == "Ana") ou le list.Any(...) de LINQ.

Comment trier une List par propriété en C# ?

Passez une comparaison à Sort : people.Sort((a, b) => a.Age.CompareTo(b.Age)) trie sur place. Échangez a et b pour l'ordre décroissant. Ou utilisez LINQ, qui renvoie une nouvelle séquence triée et garde les éléments égaux dans leur ordre d'origine : people.OrderBy(p => p.Age).ToList().

Pourquoi obtient-on « Collection was modified; enumeration operation may not execute » ?

Vous avez ajouté, supprimé ou remplacé (list[i] = x) des éléments pendant qu'un foreach parcourait la même liste, et l'énumérateur lève InvalidOperationException à l'étape suivante. Utilisez list.RemoveAll(condition), parcourez à l'envers avec une boucle for, ou itérez sur une copie comme list.ToList().

Quelle est la différence entre Count et Capacity ?

Count est le nombre d'éléments de la liste. Capacity est la taille du tableau interne, au moins égale à Count. Quand le tableau est plein, la liste en alloue un nouveau deux fois plus grand et copie les éléments, donc Add est rapide en moyenne.

Coddy programming languages illustration

Apprendre à coder avec Coddy

COMMENCER