List<T> to uporządkowana kolekcja, która rośnie i maleje w miarę dodawania i usuwania elementów. Znajduje się w System.Collections.Generic, indeksuje się ją jak tablicę (list[0]) i jest domyślnym wyborem w C#, gdy potrzebujesz "zbioru rzeczy".
Tworzenie listy i dodawanie elementów
Parametr typu w nawiasach ostrych mówi, co przechowuje lista: List<string>, List<int>, List<Order>.
Wynik:
2
Zoe, Ana, Ben, Chloe, Dev
Ana
Ana B.
3
Count to właściwość, a nie metoda (tablice używają Length, LINQ ma metodę Count(); na liście używaj właściwości). Insert przesuwa każdy dalszy element o jedno miejsce, więc wstawianie na początek dużej listy zajmuje czas proporcjonalny do jej rozmiaru. Add na końcu to tania operacja.
Usuwanie elementów
Są cztery sposoby usuwania, zależnie od tego, co wiesz o elemencie:
Wynik:
True: 85, 62, 40, 91, 55
False
62, 40, 91, 55
2 removed: 62, 91
Caught ArgumentOutOfRangeException
0
Remove przyjmuje wartość i usuwa tylko pierwsze dopasowanie. Aby usunąć wszystkie kopie wartości, użyj RemoveAll(s => s == 40). Zły indeks na liście rzuca ArgumentOutOfRangeException (tablica rzuca zamiast tego IndexOutOfRangeException), zarówno dla list[i], jak i dla RemoveAt(i). RemoveRange(index, count) usuwa cały blok.
Count a Capacity
Lista trzyma elementy w wewnętrznej tablicy. Capacity to rozmiar tej tablicy; Count to liczba zajętych miejsc. Gdy Count osiągnie Capacity, następne Add alokuje tablicę dwa razy większą i kopiuje do niej wszystko.
Wynik:
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
Podwajanie sprawia, że większość wywołań Add to tylko zapis do wolnego miejsca. Jeśli wiesz mniej więcej, ile elementów przybędzie, przekaż tę liczbę do konstruktora, aby pominąć pośrednie kopiowania. Pamiętaj, że new List<int>(1000) nadal ma Count równe 0: list[0] na takiej liście rzuca wyjątek. Pojemność to miejsce, a nie elementy.
Wyszukiwanie: Contains, IndexOf, Find, Exists
Wynik:
True
2
-1
32.00
2 cheap items
False
2
True
False
Find zwraca pierwsze dopasowanie albo wartość domyślną typu (null dla klasy), gdy nic nie pasuje, więc sprawdź wynik przed użyciem. Ostatnia linia wypisuje False, bo Contains używa Equals, a klasa bez nadpisanego Equals porównuje referencje: nowy Product z tymi samymi polami to inny obiekt. Zamiast tego szukaj według właściwości przez Exists albo Find albo nadpisz w klasie Equals i GetHashCode.
Każda z tych metod przechodzi listę od początku, więc każde wywołanie to O(n). Przy wielokrotnym wyszukiwaniu według klucza Dictionary odpowiada w stałym czasie.
Sortowanie listy
Sort() sortuje w miejscu według naturalnego porządku elementów. Przekaż lambdę porównującą, aby sortować według czegokolwiek innego.
Wynik:
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
Porównanie zwraca liczbę ujemną, gdy a powinno być pierwsze, dodatnią, gdy b, i zero przy remisie; dokładnie to daje CompareTo. W praktyce liczą się dwie różnice między Sort a OrderBy z LINQ:
Sortzmienia listę;OrderByzwraca nową sekwencję i zostawia listę w spokoju.Sortnie jest stabilne: elementy równe w porównaniu mogą zamienić się miejscami.OrderByjest stabilne, aThenBydodaje drugi klucz:players.OrderBy(p => p.Score).ThenBy(p => p.Name).
Wywołanie Sort() bez porównania na liście obiektów twojej własnej klasy rzuca InvalidOperationException, bo lista nie wie, jak uporządkować elementy. Przekaż porównanie albo zaimplementuj w klasie IComparable<T>.
Reverse() odwraca kolejność w miejscu. Ponieważ System.Linq też definiuje rozszerzenie Reverse, list.Reverse() na List<T> wybiera wersję działającą w miejscu, która nic nie zwraca.
Pętle i usuwanie w trakcie iteracji
foreach odczytuje każdy element po kolei. Pętla for daje też indeks. Nie można natomiast dodawać ani usuwać elementów w trakcie foreach po tej samej liście:
Wynik:
Caught InvalidOperationException
120, 80, 60
120, 80, 60
Wyjątek to InvalidOperationException z komunikatem "Collection was modified; enumeration operation may not execute." Pętla for idąca do przodu nie rzuca wyjątku, ale po cichu pomija element tuż za każdym usuniętym, bo wszystko przesuwa się o jeden indeks w dół. Pętla od tyłu tego unika. Trzecie rozwiązanie to iterowanie po kopii: foreach (var t in orders.ToList()).
Zmiana właściwości elementu wewnątrz foreach (na przykład order.Status = "sent") jest w porządku. Dodawanie lub usuwanie elementów psuje enumerator, podobnie jak zastąpienie elementu przez indekser (orders[i] = 0).
Konwersja między listami a tablicami
Wynik:
4
3
4, 4, 4, 4
Oslo / Lima / Pune / Kyiv
W obu kierunkach elementy są kopiowane do nowego miejsca w pamięci, więc późniejsza zmiana listy nie wpływa na tablicę. ConvertAll to własna wersja listy odpowiadająca Select(...).ToList() z LINQ. Wypisanie listy przez Console.WriteLine(list) pokazuje nazwę typu (System.Collections.Generic.List`1[System.String]); użyj string.Join.
Ściągawka
| Zadanie | Kod |
|---|---|
| Utworzenie | var l = new List<int>(); albo new List<int> { 1, 2 } |
| Dodanie na końcu | l.Add(x), l.AddRange(items) |
| Wstawienie na pozycję | l.Insert(i, x) |
| Usunięcie pierwszego dopasowania | l.Remove(x) (zwraca bool) |
| Usunięcie według indeksu | l.RemoveAt(i) |
| Usunięcie według warunku | l.RemoveAll(x => ...) (zwraca liczbę) |
| Liczba elementów | l.Count |
| Czy zawiera | l.Contains(x), l.Exists(x => ...) |
| Wyszukanie | l.Find(...), l.FindAll(...), l.FindIndex(...) |
| Sortowanie w miejscu | l.Sort(), l.Sort((a, b) => ...) |
| Posortowana kopia | l.OrderBy(x => ...).ToList() |
| Do tablicy | l.ToArray() |
Typowe błędy
- Usuwanie wewnątrz
foreach. RzucaInvalidOperationException; użyjRemoveAllalbo pętliforod tyłu. - Oczekiwanie, że
Remove(x)usunie każdą kopię. Usuwa pierwszą; użyjRemoveAll. - Używanie
Containsna obiektach bezEquals. Porównuje referencje; szukaj według właściwości przezExists. - Indeksowanie listy utworzonej z pojemnością.
new List<int>(10)jest pusta; najpierw dodaj elementy. - Założenie, że
Sortzachowuje kolejność remisów. Nie zachowuje; użyjOrderBy, gdy kolejność równych elementów ma znaczenie. - Przypisanie listy, żeby ją współdzielić, a potem zaskoczenie zmianami.
var copy = list;to ta sama lista;new List<T>(list)to kopia.
Najczęściej zadawane pytania
Jak dodać elementy do List w C#?
list.Add(item) dopisuje jeden element na końcu, list.AddRange(otherCollection) dopisuje wiele, a list.Insert(index, item) wstawia element na pozycję i przesuwa resztę dalej. Listę możesz też wypełnić przy tworzeniu: var names = new List<string> { "Ana", "Ben" };.
Jak usunąć element z List w C#?
Remove(value) usuwa pierwszy pasujący element i zwraca true, jeśli go znalazł. RemoveAt(index) usuwa według pozycji. RemoveAll(x => condition) usuwa każdy pasujący element i zwraca, ile ich usunął. Clear() opróżnia listę.
Jak sprawdzić, czy List zawiera wartość w C#?
list.Contains(value) zwraca true albo false. Porównuje przez Equals, więc dla twoich własnych klas porównuje referencje, chyba że klasa nadpisuje Equals. Aby sprawdzić według właściwości, użyj list.Exists(p => p.Name == "Ana") albo list.Any(...) z LINQ.
Jak posortować List według właściwości w C#?
Przekaż porównanie do Sort: people.Sort((a, b) => a.Age.CompareTo(b.Age)) sortuje w miejscu. Zamień a i b, aby sortować malejąco. Możesz też użyć LINQ, który zwraca nową posortowaną sekwencję i zachowuje pierwotną kolejność równych elementów: people.OrderBy(p => p.Age).ToList().
Dlaczego dostaję "Collection was modified; enumeration operation may not execute"?
Elementy zostały dodane, usunięte albo zastąpione (list[i] = x) w czasie, gdy foreach przechodziła po tej samej liście, a enumerator w następnym kroku rzuca InvalidOperationException. Użyj list.RemoveAll(condition), pętli for od tyłu albo iteruj po kopii, na przykład list.ToList().
Czym różni się Count od Capacity?
Count to liczba elementów na liście. Capacity to rozmiar wewnętrznej tablicy, który wynosi co najmniej Count. Gdy tablica się zapełni, lista alokuje nową, dwa razy większą, i kopiuje elementy, więc Add jest średnio szybkie.