Menu

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

List<T>, C#'ın büyüyebilen dizisidir. Bir liste oluşturmayı, öğe eklemeyi ve araya eklemeyi, değere, indekse ya da koşula göre silmeyi, Contains ve Find ile aramayı, bir property'ye göre sıralamayı ve foreach içinde listeyi değiştirmenin yol açtığı hatadan kaçınmayı öğrenin.

Bu sayfada çalıştırılabilir editörler var - düzenle, çalıştır ve sonucu anında gör.

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:

  • Sort listeyi değiştirir; OrderBy yeni bir dizi döndürür ve listeye dokunmaz.
  • Sort kararlı değildir: eşit karşılaştırılan öğeler yer değiştirebilir. OrderBy kararlıdır ve ThenBy ikinci 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örevKod
Oluşturmakvar l = new List<int>(); ya da new List<int> { 1, 2 }
Sona eklemekl.Add(x), l.AddRange(items)
Bir konuma eklemekl.Insert(i, x)
İlk eşleşmeyi silmekl.Remove(x) (bool döndürür)
İndekse göre silmekl.RemoveAt(i)
Koşula göre silmekl.RemoveAll(x => ...) (sayı döndürür)
Öğe sayısıl.Count
İçeriyor mul.Contains(x), l.Exists(x => ...)
Bulmakl.Find(...), l.FindAll(...), l.FindIndex(...)
Yerinde sıralamakl.Sort(), l.Sort((a, b) => ...)
Sıralı kopyal.OrderBy(x => ...).ToList()
Diziyel.ToArray()

Yaygın hatalar

  • foreach içinde silmek. InvalidOperationException fırlatır; RemoveAll ya da geriye doğru bir for döngüsü kullanın.
  • Remove(x)'in her kopyayı silmesini beklemek. İlkini siler; RemoveAll kullanın.
  • Equals'ı olmayan nesnelerde Contains kullanmak. Referansları karşılaştırır; Exists ile 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 önemliyse OrderBy kullanı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.

Coddy programming languages illustration

Coddy ile kodlamayı öğren

BAŞLA