List<T>, öğe ekleyip çıkardıkça büyüyen ve küçülen sıralı bir koleksiyondur. System.Collections.Generic içinde yaşar, bir dizi gibi indekslenir (list[0]) ve C#'ta "bir yığın şey" için varsayılan seçimdir.
Bir liste oluşturmak ve öğe eklemek
Açılı parantezlerdeki tip parametresi listenin ne tuttuğunu söyler: List<string>, List<int>, List<Order>.
Çıktı:
2
Zoe, Ana, Ben, Chloe, Dev
Ana
Ana B.
3
Count bir metot değil property'dir (diziler Length kullanır, LINQ'in bir Count() metodu vardır; bir listede property'yi kullanın). Insert sonraki her öğeyi bir konum kaydırır, bu yüzden büyük bir listenin başına eklemek boyutuyla orantılı zaman alır. Sona Add ucuz işlemdir.
Öğe silmek
Öğe hakkında ne bildiğinize bağlı olarak silmenin dört yolu vardır:
Çıktı:
True: 85, 62, 40, 91, 55
False
62, 40, 91, 55
2 removed: 62, 91
Caught ArgumentOutOfRangeException
0
Remove bir değer alır ve yalnızca ilk eşleşmeyi siler. Bir değerin tüm kopyalarını silmek için RemoveAll(s => s == 40) kullanın. Bir listede hatalı bir indeks hem list[i] hem de RemoveAt(i) için ArgumentOutOfRangeException fırlatır (bir dizi ise IndexOutOfRangeException fırlatır). RemoveRange(index, count) bir bloğu siler.
Count ile Capacity
Bir liste öğelerini içeride bir dizide tutar. Capacity o dizinin boyutudur; Count kaç yuvanın kullanıldığıdır. Count Capacity'ye ulaştığında sonraki Add iki kat büyük bir dizi ayırır ve her şeyi kopyalar.
Çıktı:
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
İkiye katlamak, çoğu Add çağrısının boş bir yuvaya yazmaktan ibaret olduğu anlamına gelir. Kabaca kaç öğe geleceğini biliyorsanız ara kopyaları atlamak için sayıyı constructor'a verin. new List<int>(1000)'in Count'unun yine 0 olduğuna dikkat edin: üzerinde list[0] istisna fırlatır. Kapasite yerdir, öğe değil.
Aramak: Contains, IndexOf, Find, Exists
Çıktı:
True
2
-1
32.00
2 cheap items
False
2
True
False
Find ilk eşleşmeyi ya da hiçbir şey eşleşmediğinde tipin varsayılan değerini (bir sınıf için null) döndürür, bu yüzden sonucu kullanmadan önce kontrol edin. Son satır False yazdırır, çünkü Contains Equals kullanır ve Equals override'ı olmayan bir sınıf referansları karşılaştırır: aynı alanlara sahip yeni bir Product farklı bir nesnedir. Bunun yerine Exists ya da Find ile bir property'ye göre arayın ya da sınıfta Equals ve GetHashCode'u override edin.
Bu metotların her biri listeyi baştan dolaşır, bu yüzden her çağrı O(n)'dir. Bir anahtara göre tekrarlanan aramalar için bir Dictionary sabit zamanda cevap verir.
Bir listeyi sıralamak
Sort() öğelerin doğal sırasını kullanarak yerinde sıralar. Başka bir şeye göre sıralamak için bir karşılaştırma lambda'sı verin.
Çıktı:
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
Bir karşılaştırma, a önce gelmeliyse negatif, b önce gelmeliyse pozitif, eşitlerse sıfır döndürür; CompareTo tam olarak bunu üretir. Sort ile LINQ'in OrderBy'ı arasındaki iki fark uygulamada önemlidir:
Sortlisteyi değiştirir;OrderByyeni bir dizi döndürür ve listeye dokunmaz.Sortkararlı değildir: eşit karşılaştırılan öğeler yer değiştirebilir.OrderBykararlıdır veThenByikinci bir anahtar ekler:players.OrderBy(p => p.Score).ThenBy(p => p.Name).
Kendi sınıfınızdan oluşan bir listede karşılaştırma olmadan Sort() çağırmak InvalidOperationException fırlatır, çünkü liste öğeleri nasıl sıralayacağını bilmez. Ya bir karşılaştırma verin ya da sınıfta IComparable<T> uygulayın.
Reverse() yerinde ters çevirir. System.Linq de bir Reverse extension'ı tanımladığı için bir List<T> üzerinde list.Reverse() hiçbir şey döndürmeyen yerinde sürümü seçer.
Döngü ve dolaşırken silme
foreach her öğeyi sırayla okur. Bir for döngüsü size indeksi de verir. Yapamayacağınız şey, aynı liste üzerindeki bir foreach'in ortasında öğe eklemek ya da silmektir:
Çıktı:
Caught InvalidOperationException
120, 80, 60
120, 80, 60
İstisna, "Collection was modified; enumeration operation may not execute." mesajlı InvalidOperationException'dır. İleri doğru bir for döngüsü istisna fırlatmaz, ama sildiğiniz her öğeden hemen sonrakini sessizce atlar, çünkü her şey bir indeks aşağı kayar. Geriye doğru dönmek bundan kaçınır. Üçüncü bir çözüm bir kopya üzerinde dolaşmaktır: foreach (var t in orders.ToList()).
foreach içinde bir öğenin property'sini değiştirmek (örneğin order.Status = "sent") sorun değildir. Öğe eklemek ya da silmek enumerator'ı bozar, indeksleyici üzerinden birini değiştirmek (orders[i] = 0) de öyle.
Listeler ve diziler arasında dönüşüm
Çıktı:
4
3
4, 4, 4, 4
Oslo / Lima / Pune / Kyiv
İki yön de elemanları yeni bir depolamaya kopyalar, bu yüzden listeyi sonradan değiştirmek diziyi etkilemez. ConvertAll, listenin LINQ'teki Select(...).ToList()'in kendi sürümüdür. Bir listeyi Console.WriteLine(list) ile yazdırmak tip adını gösterir (System.Collections.Generic.List`1[System.String]); string.Join kullanın.
Hızlı başvuru
| Görev | Kod |
|---|---|
| Oluşturmak | var l = new List<int>(); ya da new List<int> { 1, 2 } |
| Sona eklemek | l.Add(x), l.AddRange(items) |
| Bir konuma eklemek | l.Insert(i, x) |
| İlk eşleşmeyi silmek | l.Remove(x) (bool döndürür) |
| İndekse göre silmek | l.RemoveAt(i) |
| Koşula göre silmek | l.RemoveAll(x => ...) (sayı döndürür) |
| Öğe sayısı | l.Count |
| İçeriyor mu | l.Contains(x), l.Exists(x => ...) |
| Bulmak | l.Find(...), l.FindAll(...), l.FindIndex(...) |
| Yerinde sıralamak | l.Sort(), l.Sort((a, b) => ...) |
| Sıralı kopya | l.OrderBy(x => ...).ToList() |
| Diziye | l.ToArray() |
Yaygın hatalar
foreachiçinde silmek.InvalidOperationExceptionfırlatır;RemoveAllya da geriye doğru birfordöngüsü kullanın.Remove(x)'in her kopyayı silmesini beklemek. İlkini siler;RemoveAllkullanın.Equals'ı olmayan nesnelerdeContainskullanmak. Referansları karşılaştırır;Existsile property'ye göre arayın.- Bir kapasiteyle oluşturulmuş bir listeyi indekslemek.
new List<int>(10)boştur; önce öğe ekleyin. Sort'un eşitleri sırada tuttuğunu varsaymak. Tutmaz; eşitler arasındaki sıra önemliyseOrderBykullanın.- Paylaşmak için bir listeyi atayıp sonra değişikliklere şaşırmak.
var copy = list;aynı listedir;new List<T>(list)bir kopyadır.
Sıkça Sorulan Sorular
C#'ta bir List'e nasıl öğe eklenir?
list.Add(item) sona bir öğe ekler, list.AddRange(otherCollection) birçok öğe ekler ve list.Insert(index, item) bir öğeyi bir konuma koyup geri kalanları kaydırır. Bir listeyi oluştururken de doldurabilirsiniz: var names = new List<string> { "Ana", "Ben" };.
C#'ta bir List'ten öğe nasıl silinir?
Remove(value) ilk eşleşen öğeyi siler ve bir tane bulduysa true döndürür. RemoveAt(index) konuma göre siler. RemoveAll(x => condition) eşleşen her öğeyi siler ve kaç tane sildiğini döndürür. Clear() listeyi boşaltır.
C#'ta bir List'in bir değer içerip içermediği nasıl kontrol edilir?
list.Contains(value) true ya da false döndürür. Equals ile karşılaştırır, bu yüzden kendi sınıflarınız için sınıf Equals'ı override etmedikçe referansları karşılaştırır. Bir property'ye göre kontrol etmek için list.Exists(p => p.Name == "Ana") ya da LINQ'in list.Any(...)'ini kullanın.
C#'ta bir List bir property'ye göre nasıl sıralanır?
Sort'a bir karşılaştırma verin: people.Sort((a, b) => a.Age.CompareTo(b.Age)) yerinde sıralar. Azalan sıra için a ile b'nin yerini değiştirin. Ya da yeni bir sıralı dizi döndüren ve eşit öğeleri orijinal sıralarında tutan LINQ'i kullanın: people.OrderBy(p => p.Age).ToList().
Neden "Collection was modified; enumeration operation may not execute" hatası alıyorum?
Bir foreach aynı liste üzerinde dönerken öğe eklediniz, sildiniz ya da değiştirdiniz (list[i] = x) ve enumerator bir sonraki adımında InvalidOperationException fırlatıyor. list.RemoveAll(condition) kullanın, bir for döngüsüyle geriye doğru dönün ya da list.ToList() gibi bir kopya üzerinde dolaşın.
Count ile Capacity arasındaki fark nedir?
Count listedeki öğe sayısıdır. Capacity iç dizinin boyutudur ve en az Count kadardır. Dizi dolduğunda liste iki kat büyüklükte yeni bir dizi ayırır ve öğeleri kopyalar, bu yüzden Add ortalamada hızlıdır.