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 :
Sortmodifie la liste ;OrderByrenvoie une nouvelle séquence et laisse la liste intacte.Sortn'est pas stable : des éléments égaux peuvent échanger leurs places.OrderByest stable, etThenByajoute 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âche | Code |
|---|---|
| Créer | var l = new List<int>(); ou new List<int> { 1, 2 } |
| Ajouter à la fin | l.Add(x), l.AddRange(items) |
| Insérer à une position | l.Insert(i, x) |
| Supprimer la première correspondance | l.Remove(x) (renvoie un bool) |
| Supprimer par index | l.RemoveAt(i) |
| Supprimer par condition | l.RemoveAll(x => ...) (renvoie le nombre) |
| Nombre d'éléments | l.Count |
| Contient | l.Contains(x), l.Exists(x => ...) |
| Trouver | l.Find(...), l.FindAll(...), l.FindIndex(...) |
| Trier sur place | l.Sort(), l.Sort((a, b) => ...) |
| Copie triée | l.OrderBy(x => ...).ToList() |
| Vers un tableau | l.ToArray() |
Erreurs courantes
- Supprimer dans un
foreach. Cela lèveInvalidOperationException; utilisezRemoveAllou une boucleforà l'envers. - S'attendre à ce que
Remove(x)supprime chaque copie. Il supprime la première ; utilisezRemoveAll. - Utiliser
Containssur des objets sansEquals. Cela compare des références ; cherchez par propriété avecExists. - Indexer une liste créée avec une capacité.
new List<int>(10)est vide ; ajoutez d'abord des éléments. - Supposer que
Sortgarde l'ordre des égalités. Ce n'est pas le cas ; utilisezOrderByquand 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.