HashSet <T> ve List <T> arasındaki fark nedir?


156

.NET HashSet<T>ve List<T>.NET arasındaki farkın ne olduğunu açıklayabilir misiniz ?

Belki hangi durumlarda HashSet<T>tercih edilmeli diye bir örnekle açıklayabilirsiniz List<T>?



En.wikipedia.org/wiki/Hash_table ve en.wikipedia.org/wiki/Dynamic_array ile ilgili Wikipedia makalelerine göz atmanızı öneririm .
mqp

Performansla ilgili bilgi için, bkz. Hashset-vs-list-performance
nawfal

Yanıtlar:


213

Listenin aksine <> ...

  1. HashSet, yinelenen üyesi olmayan bir Listedir.

  2. Bir HashSet yalnızca benzersiz girişleri içerecek şekilde kısıtlandığından, dahili yapı arama için optimize edilmiştir (bir listeyle karşılaştırıldığında) - oldukça hızlıdır

  3. Bir HashSet öğesine eklemek bir Boolean döndürür - Set'te zaten mevcut olduğundan ekleme başarısız olursa false

  4. Kümeye karşı matematiksel küme işlemleri gerçekleştirebilir: Birlik / Kavşak / IsSubsetOf vb.

  5. HashSet yalnızca IList ICollection uygulamıyor

  6. Bir HashSet ile indeksleri kullanamazsınız, sadece numaralandırıcılardır.

Bir HashSet kullanmanın ana nedeni, Set işlemlerini yapmakla ilgileniyorsanız olabilir.

Verilen 2 set: hashSet1 ve hashSet2

 //returns a list of distinct items in both sets
 HashSet set3 = set1.Union( set2 );

LINQ kullanarak eşdeğer bir işlemle karşılaştırıldığında uçar. Ayrıca yazmak daha da temiz!


IDK, Unionyöntemle ilgili problemlerim vardı . Onun UnionWithyerine kullanmıştım .
kullanıcı

2
+1 için "HashedSet kullanmanın ana nedeni, Set işlemlerini yapmakla ilgileniyorsanız olabilir."
LCJ

12
Aslında, koleksiyonunuzu "çanta öğeleri" olarak değerlendirebileceğiniz durumlarda HashSet'lerin uygun olduğuna işaret eden yanıtı tercih ediyorum. Set işlemleri Muhafaza kontrolleri kadar sık ​​değildir. Bir dizi benzersiz öğeye (örn. Kodlar) sahip olduğunuz ve sınırlama olup olmadığını kontrol etmeniz gereken herhangi bir noktada bir HashSet kullanışlıdır.
ThunderGr

İyi cevap. Birkaç performans karakteristik farklılığı da eklemek istiyorum.
nawfal

1
Soru: Ana sebep, yinelenen öğelerin olmamasının kesinliğine sahip olmamak mı?
Andrea Scarafoni

54

Daha kesin olmak gerekirse örneklerle gösterelim,

HashSet'i aşağıdaki örnekte olduğu gibi kullanamazsınız.

HashSet<string> hashSet1 = new HashSet<string>(){"1","2","3"};
for (int i = 0; i < hashSet1.Count; i++)
    Console.WriteLine(hashSet1[i]);

hashSet1[i] bir hata oluşturur:

'System.Collections.Generic.HashSet' türündeki bir ifadeye [] ile dizin oluşturma uygulanamıyor

Foreach ifadesini kullanabilirsiniz:

foreach (var item in hashSet1)
    Console.WriteLine(item);

Liste bunu yapmanıza izin verirken HashSet'e yinelenen öğeler ekleyemezsiniz ve HashSet'e bir öğe eklerken, öğenin içerip içermediğini kontrol edebilirsiniz.

HashSet<string> hashSet1 = new HashSet<string>(){"1","2","3"};
if (hashSet1.Add("1"))
   Console.WriteLine("'1' is successfully added to hashSet1!");
else
   Console.WriteLine("'1' could not be added to hashSet1, because it contains '1'");

HashSet gibi bazı yararlı işlevleri vardır IntersectWith, UnionWith, IsProperSubsetOf, ExceptWith, SymmetricExceptWithvb

IsProperSubsetOf:

HashSet<string> hashSet1 = new HashSet<string>() { "1", "2", "3", "4" };
HashSet<string> hashSet2 = new HashSet<string>() { "2", "4", "6", "8" };
HashSet<string> hashSet3 = new HashSet<string>() { "1", "2", "3", "4", "5" };
if (hashSet1.IsProperSubsetOf(hashSet3))
    Console.WriteLine("hashSet3 contains all elements of hashSet1.");
if (!hashSet1.IsProperSubsetOf(hashSet2))
    Console.WriteLine("hashSet2 does not contains all elements of hashSet1.");

UnionWith:

HashSet<string> hashSet1 = new HashSet<string>() { "3", "4" };
HashSet<string> hashSet2 = new HashSet<string>() { "2", "4", "6", "8" };
hashSet1.UnionWith(hashSet2); //hashSet1 -> 3, 2, 4, 6, 8

IntersectWith:

HashSet<string> hashSet1 = new HashSet<string>() { "3", "4", "8" };
HashSet<string> hashSet2 = new HashSet<string>() { "2", "4", "6", "8" }
hashSet1.IntersectWith(hashSet2);//hashSet1 -> 4, 8

ExceptWith :

 HashSet<string> hashSet1 = new HashSet<string>() { "1", "2", "3", "5", "6" };
 HashSet<string> hashSet2 = new HashSet<string>() { "1", "2", "3", "4" };
 hashSet1.ExceptWith(hashSet2);//hashSet1 -> 5, 6

SymmetricExceptWith :

 HashSet<string> hashSet1 = new HashSet<string>() { "1", "2", "3", "5", "6" };
 HashSet<string> hashSet2 = new HashSet<string>() { "1", "2", "3", "4" };
 hashSet1.SymmetricExceptWith(hashSet2);//hashSet1 -> 4, 5, 6

Bu arada, sipariş HashSets'te korunmaz. Örnekte, son olarak "2" öğesini ekledik ancak ikinci sırada bulunuyor:

HashSet<string> hashSet1 = new HashSet<string>() { "3", "4", "8" };
hashSet1.Add("1");    // 3, 4, 8, 1
hashSet1.Remove("4"); // 3, 8, 1
hashSet1.Add("2");    // 3, 2 ,8, 1

51

A HashSet<T>, O(1)kontrol altına almak için size bakmak üzere tasarlanmış bir sınıftır (yani, bu koleksiyon belirli bir nesneyi içeriyor mu ve cevabı hızlı bir şekilde söylüyor mu).

A List<T>, O(1)dinamik olarak büyüyebilecek (dinamik diziyi düşünün) size rastgele erişime sahip bir koleksiyon vermek için tasarlanmış bir sınıftır . Sınırlamayı O(n)zamanında test edebilirsiniz (liste sıralanmadıysa, zaman içinde ikili arama yapabilirsiniz O(log n)).

Belki hangi davalara HashSet<T>karşı tercih edilmesi gerektiğini bir örnekle açıklayabilirsinizList<T>

Sınırlama özelliğini test etmek istediğinizde O(1).


Liste sıralıysa O (log n) hariç; sonuçta sıralanmamış bir listede arama yapmaktan daha hızlıdır.
Andrei

20

Aşağıdakileri List<T>yapmak istediğinizde bir kullanın:

  • Bir öğe koleksiyonunu belirli bir sırada saklayın.

İstediğiniz öğenin dizinini biliyorsanız (öğenin değerinden ziyade) geri çağırılır O(1). Dizini bilmiyorsanız, O(n)sıralanmamış bir koleksiyon için öğeyi bulmak daha fazla zaman alır .

Aşağıdakileri Hashset<T>yapmak istediğinizde bir kullanın:

  • Bir koleksiyonda belirli bir nesnenin bulunup bulunmadığını çabucak bulun.

Bulmak istediğiniz şeyin adını biliyorsanız, Arama O(1)(bu 'Karma' kısmıdır). Bunun gibi bir sıralamayı List<T>korumaz ve kopyaları depolayamazsınız (kopyayı eklemenin bir etkisi yoktur, bu 'Ayarla' bölümüdür).

A'nın ne zaman kullanılacağına bir örnek, Hashset<T>Scrabble oyununda oynanan bir kelimenin İngilizce (veya başka bir dilde) geçerli bir kelime olup olmadığını öğrenmek isterseniz verilebilir. Böyle bir oyunun çevrimiçi sürümünün tüm örnekleri tarafından kullanılmak üzere bir web hizmeti oluşturmak isteseniz daha iyi olur.

A List<T>, oyuncu skorlarını izlemek için skorbord oluşturmak için iyi bir veri yapısı olacaktır.


15

Liste sıralı bir listedir. Bu

  • bir tamsayı dizini tarafından erişildi
  • kopya içerebilir
  • öngörülebilir bir sırası var

HashSet bir kümedir. O:

  • Yinelenen öğeleri engelleyebilir (bkz. Ekle (T) )
  • Set içindeki öğelerin sırasını garanti etmez
  • Bir sette bekleyebileceğiniz işlemler vardır, örneğin IntersectWith, IsProperSubsetOf, UnionWith.

Koleksiyonunuza, öğeleri ekleyebileceğiniz, ekleyebileceğiniz ve kaldırabileceğiniz bir dizi gibi görünmek istediğinizde liste daha uygundur. Koleksiyonunuzu, siparişin önemli olmadığı öğelerin bir "torbası" gibi işlemek veya IntersectWith veya UnionWith gibi işlemleri kullanarak diğer setlerle karşılaştırmak istediğinizde HashSet daha iyi bir seçimdir.



3

Liste, bir dizinin aksine giriş ekleyip kaldırabileceğiniz T Tipi nesnelerin sıralı bir koleksiyonudur.

Üyeleri sakladığınız sırada başvurmak istediğiniz bir liste kullanırsınız ve bu öğelere öğenin kendisi yerine bir konumla erişirsiniz.

Bir HashSet, değerin yanı sıra öğenin kendisinin de anahtar olduğu bir sözlük gibidir, sipariş garanti edilmez.

Bir nesnenin koleksiyonda olup olmadığını kontrol etmek istediğiniz bir HashSet kullanırsınız


1
Açıklığa kavuşturmak için, başkalarının ilk bakışta yanlış okuması durumunda - Listbir emir tutar (yani şeyler eklendiğinde), ancak öğeleri otomatik olarak sıralamaz. Telefon etmeniz .Sortveya kullanmanız gerekir SortedList.
drzaus

1

Bu veri yapılarını veri güdümlü geliştirmede gerçek kullanıma uygulamaya karar verirseniz, bir HashSet, veri temizleme ve taşıma için veri bağdaştırıcısı kaynaklarına karşı çoğaltmanın sınanmasında ÇOK yardımcı olur.

Ayrıca, DataAnnotations Sınıfı kullanılıyorsa, sınıf özellikleri üzerinde Anahtar mantığı uygulanabilir ve bir Liste uygulamasında bunun çok zor olacağı bir HashSet ile Doğal Dizini (kümelenmiş veya kümelenmemiş) etkili bir şekilde kontrol edebilirsiniz.

Bir listeyi kullanmak için güçlü bir seçenek, bir DropDownList Yardımcısı için bir MVC Görünümü'ne sınıfların bir listesini göndermek ve ayrıca WebApi üzerinden JSON yapısı olarak göndermek gibi bir Görünüm Modelinde birden çok ortam için jenerikler uygulamaktır. Liste tipik sınıf toplama mantığına izin verir ve tek bir görünüm modelinin farklı ortamlara hesaplanmasına yönelik daha "Arayüz" gibi bir yaklaşım için esnekliği korur.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.