Apa perbedaan antara HashSet <T> dan Daftar <T>?

156

Bisakah Anda menjelaskan apa perbedaan antara HashSet<T>dan List<T>. NET?

Mungkin Anda bisa menjelaskan dengan contoh dalam kasus apa yang HashSet<T>lebih disukai List<T>?

kue pensil
sumber
22
Beberapa bacaan tentang topik: C # /. NET Fundamentals: Memilih Kelas Collection yang Tepat
Fredrik Mörk
Saya sarankan Anda membaca artikel Wikipedia di en.wikipedia.org/wiki/Hash_table dan en.wikipedia.org/wiki/Dynamic_array .
mqp
Untuk kinerja terkait, lihat hashset-vs-list-performance
nawfal

Jawaban:

213

Tidak seperti Daftar <> ...

  1. HashSet adalah Daftar tanpa anggota duplikat.

  2. Karena HashSet dibatasi hanya berisi entri unik, struktur internal dioptimalkan untuk pencarian (dibandingkan dengan daftar) - itu jauh lebih cepat

  3. Menambahkan ke HashSet mengembalikan boolean - false jika penambahan gagal karena sudah ada di Set

  4. Dapat melakukan operasi set matematis terhadap Set: Union / Intersection / IsSubsetOf dll.

  5. HashSet tidak menerapkan ICollection hanya IList

  6. Anda tidak dapat menggunakan indeks dengan HashSet, hanya enumerator.

Alasan utama untuk menggunakan HashSet adalah jika Anda tertarik untuk melakukan operasi Set.

Diberikan 2 set: hashSet1 dan hashSet2

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

terbang dibandingkan dengan operasi yang setara menggunakan LINQ. Menulis juga lebih rapi!

BonyT
sumber
IDK, saya punya masalah dengan Unionmetode. Saya telah menggunakan UnionWithsebagai gantinya.
pengguna
2
+1 untuk "Alasan utama untuk menggunakan HashedSet adalah jika Anda tertarik untuk melakukan operasi Set."
LCJ
12
Sebenarnya, saya lebih suka jawaban yang menunjukkan bahwa HashSets cocok jika Anda dapat memperlakukan koleksi Anda sebagai "item tas". Atur operasi tidak begitu sering seperti pemeriksaan Kontainmen. Pada titik mana pun Anda memiliki serangkaian item unik (mis. Kode) dan Anda perlu memeriksa kontainmen, HashSet berguna.
ThunderGr
Jawaban yang bagus. Saya tergoda untuk menambahkan beberapa perbedaan karakteristik kinerja juga.
nawfal
1
Pertanyaan: alasan utamanya adalah tidak memiliki kepastian untuk tidak memiliki item duplikat?
Andrea Scarafoni
54

Agar lebih tepat mari kita tunjukkan dengan contoh,

Anda tidak dapat menggunakan HashSet seperti pada contoh berikut.

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

hashSet1[i] akan menghasilkan kesalahan:

Tidak dapat menerapkan pengindeksan dengan [] ke ekspresi dari tipe 'System.Collections.Generic.HashSet'

Anda dapat menggunakan foreach statement:

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

Anda tidak dapat menambahkan item duplikat ke HashSet sementara Daftar memungkinkan Anda untuk melakukan ini dan saat Anda menambahkan item ke HashSet, Anda dapat memeriksa apakah itu berisi item atau tidak.

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 memiliki beberapa fungsi yang berguna seperti IntersectWith, UnionWith, IsProperSubsetOf, ExceptWith, SymmetricExceptWithdll

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

Omong-omong, pesanan tidak disimpan dalam HashSets. Dalam contoh, kami menambahkan elemen "2" terakhir tetapi berada di urutan kedua:

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
GorkemHalulu
sumber
51

A HashSet<T>adalah kelas yang dirancang untuk memberi Anda O(1)pencarian untuk penahanan (yaitu, apakah koleksi ini mengandung objek tertentu, dan katakan padaku jawabannya dengan cepat).

A List<T>adalah kelas yang dirancang untuk memberi Anda koleksi dengan O(1)akses acak daripada yang dapat tumbuh secara dinamis (pikirkan array dinamis). Anda dapat menguji penahanan dalam O(n)waktu (kecuali daftar diurutkan, maka Anda dapat melakukan pencarian biner dalam O(log n)waktu).

Mungkin Anda bisa menjelaskan dengan contoh dalam kasus apa yang HashSet<T>harus disukaiList<T>

Ketika Anda ingin menguji penahanan di O(1).

jason
sumber
Kecuali O (log n) jika daftar diurutkan; itu, bagaimanapun, lebih cepat daripada mencari dalam daftar yang tidak disortir.
Andrei
20

Gunakan List<T>ketika Anda ingin:

  • Menyimpan koleksi barang dalam urutan tertentu.

Jika Anda tahu indeks dari item yang Anda inginkan (bukan nilai item itu sendiri) pengambilan adalah O(1). Jika Anda tidak tahu indeksnya, mencari item membutuhkan lebih banyak waktu, O(n)untuk koleksi yang tidak disortir.

Gunakan Hashset<T>ketika Anda ingin:

  • Cepat mencari tahu apakah objek tertentu terkandung dalam koleksi.

Jika Anda tahu nama benda yang ingin Anda temukan, Cari O(1)(itu bagian 'Hash'). Itu tidak mempertahankan pemesanan seperti yang List<T>dilakukan dan Anda tidak dapat menyimpan duplikat (menambahkan duplikat tidak berpengaruh, itulah bagian 'Set').

Contoh kapan harus menggunakan Hashset<T>adalah jika Anda ingin mengetahui apakah kata yang dimainkan di permainan Scrabble adalah kata yang valid dalam bahasa Inggris (atau bahasa lain). Bahkan lebih baik jika Anda ingin membangun layanan web untuk digunakan oleh semua contoh versi online dari permainan seperti itu.

A List<T>akan menjadi struktur data yang baik untuk membuat papan skor untuk melacak skor pemain.

Waylon Flinn
sumber
15

Daftar adalah daftar yang diurutkan. ini

  • diakses oleh indeks integer
  • dapat berisi duplikat
  • memiliki pesanan yang dapat diprediksi

HashSet adalah himpunan. Itu:

  • Dapat memblokir item duplikat (lihat Tambah (T) )
  • Tidak menjamin urutan barang dalam set
  • Memiliki operasi yang Anda harapkan pada set, misalnya , IntersectWith, IsProperSubsetOf, UnionWith.

Daftar lebih tepat ketika Anda ingin mengakses koleksi Anda seolah-olah itu seperti sebuah array yang dapat Anda tambahkan, masukkan dan hapus item. HashSet adalah pilihan yang lebih baik jika Anda ingin memperlakukan koleksi Anda seperti "tas" item yang urutannya tidak penting atau ketika Anda ingin membandingkannya dengan set lain menggunakan operasi seperti IntersectWith atau UnionWith.

dgvid
sumber
3

Daftar belum tentu unik, sementara hashset, untuk satu.

di sana ada konektor
sumber
3

Daftar adalah kumpulan objek yang diurutkan dari Tipe T yang tidak seperti array, Anda dapat menambah dan menghapus entri.

Anda akan menggunakan daftar di mana Anda ingin mereferensikan anggota dalam urutan Anda menyimpannya dan Anda mengaksesnya dengan posisi daripada item itu sendiri.

HashSet seperti kamus bahwa item itu sendiri adalah kunci serta nilainya, pemesanan tidak dijamin.

Anda akan menggunakan HashSet di mana Anda ingin memeriksa bahwa suatu objek ada di koleksi

Bob Vale
sumber
1
Untuk memperjelas, jika ada orang yang membaca yang salah pada pandangan pertama - Listmempertahankan pesanan (yaitu ketika hal-hal ditambahkan), tetapi tidak secara otomatis mengurutkan item. Anda harus menelepon .Sortatau menggunakan a SortedList.
drzaus
1

Jika Anda memutuskan untuk menerapkan struktur data ini untuk penggunaan aktual dalam pengembangan berbasis data, HashSet sangat membantu dalam menguji replikasi terhadap sumber adaptor data, untuk pembersihan data dan migrasi.

Juga, jika menggunakan Kelas DataAnnotations, seseorang dapat menerapkan logika Kunci pada properti kelas dan secara efektif mengontrol Indeks Alami (berkerumun atau tidak) dengan HashSet, di mana ini akan sangat sulit dalam implementasi Daftar.

Opsi kuat untuk menggunakan daftar adalah untuk mengimplementasikan generik untuk beberapa media pada Model Tampilan, seperti mengirim daftar kelas ke Tampilan MVC untuk DropDownList Helper, dan juga untuk mengirim sebagai konstruk JSON melalui WebApi. Daftar ini memungkinkan logika kumpulan kelas tipikal, dan menjaga fleksibilitas untuk pendekatan yang lebih mirip "Antarmuka" untuk menghitung model tampilan tunggal ke media yang berbeda.

Nathan Teague
sumber