Perbedaan antara Pencarian () dan Kamus (Dari daftar ())

165

Saya mencoba untuk membungkus kepala saya di sekitar struktur data mana yang paling efisien dan kapan / di mana menggunakan yang mana.

Sekarang, bisa jadi saya hanya tidak mengerti strukturnya dengan cukup baik, tetapi bagaimana ILookup(of key, ...)perbedaannya Dictionary(of key, list(of ...))?

Juga di mana saya ingin menggunakan ILookupdan di mana akan lebih efisien dalam hal kecepatan program / memori / mengakses data, dll?

John Bustos
sumber
1
orang mungkin juga ingin melihat apa-apa-the-point-of-lookuptkey-telement
nawfal

Jawaban:

255

Dua perbedaan signifikan:

  • Lookuptidak kekal. Yay :) (Setidaknya, saya percaya Lookupkelas konkretnya tidak dapat diubah, dan ILookupantarmuka tidak menyediakan anggota yang bermutasi. Mungkin saja ada implementasi yang dapat diubah lainnya.)
  • Saat Anda mencari kunci yang tidak ada dalam pencarian, Anda mendapatkan urutan kosong kembali bukan KeyNotFoundException. (Karenanya tidak ada TryGetValue, AFAICR.)

Mereka cenderung setara dalam efisiensi - pencarian mungkin menggunakan Dictionary<TKey, GroupingImplementation<TValue>>belakang layar, misalnya. Pilih di antara mereka berdasarkan kebutuhan Anda. Secara pribadi saya menemukan bahwa pencarian biasanya lebih cocok daripada Dictionary<TKey, List<TValue>>, sebagian besar karena dua poin pertama di atas.

Perhatikan bahwa sebagai detail implementasi, implementasi konkret IGrouping<,>yang digunakan untuk implementasi nilai IList<TValue>, yang berarti efisien untuk digunakan bersama Count(), ElementAt()dll.

Jon Skeet
sumber
Jika pencarian kunci yang tidak ada menghasilkan urutan kosong daripada pengecualian, maka sangat tidak dapat digunakan sebagai imo pengumpulan tujuan umum. Ini agak ok dalam kasus koleksi abadi yang merupakan produk sampingan dari permintaan LINQ.
nawfal
@nawfal - untuk itulah tepatnya pencarian. Dari msdn : "Anda dapat membuat turunan dari Lookup <TKey, TElement> dengan memanggil ToLookup pada objek yang mengimplementasikan IEnumerable <T>."
Niall Connaughton
50

Menarik bahwa tidak ada yang menyatakan perbedaan terbesar sebenarnya (Diambil langsung dari MSDN ):

Pencarian mirip dengan Kamus. Perbedaannya adalah bahwa Kamus memetakan kunci ke nilai tunggal, sedangkan Pencarian memetakan kunci untuk koleksi nilai.

Mladen Mihajlovic
sumber
51
Periksa pertanyaan: ini tentang perbedaan antara Pencarian <TKey, TValue> dan Kamus <TKey, Daftar <TValue>>, sehingga perbedaan sudah agak eksplisit.
Martao
5
@Martao beberapa orang menemukan pertanyaan ini ketika googling untuk memahami perbedaan antara pencarian dan kamus. Jawaban ini sangat berguna.
jakubiszon
34

Baik a Dictionary<Key, List<Value>>dan secara Lookup<Key, Value>logis dapat menyimpan data yang diorganisasikan dengan cara yang serupa dan keduanya memiliki tingkat efisiensi yang sama. Perbedaan utama adalah a Lookuptidak dapat diubah: ia tidak memiliki Add()metode dan tidak ada konstruktor publik (dan seperti yang disebutkan Jon Anda dapat meminta kunci yang tidak ada tanpa pengecualian dan memiliki kunci sebagai bagian dari pengelompokan).

Seperti yang Anda gunakan, itu benar-benar tergantung pada bagaimana Anda ingin menggunakannya. Jika Anda mempertahankan peta kunci untuk beberapa nilai yang terus-menerus dimodifikasi, maka a Dictionary<Key, List<Value>>mungkin lebih baik karena dapat diubah.

Namun, jika Anda memiliki urutan data dan hanya ingin tampilan baca-saja dari data yang diatur oleh kunci, maka pencarian sangat mudah dibangun dan akan memberi Anda snapshot hanya-baca.

James Michael Hare
sumber
11

Perbedaan utama antara a ILookup<K,V>dan a Dictionary<K, List<V>>adalah kamus bisa berubah; Anda dapat menambah atau menghapus kunci, dan juga menambah atau menghapus item dari daftar yang dicari. Sebuah ILookuptidak berubah dan tidak dapat dimodifikasi setelah dibuat.

Implementasi yang mendasari kedua mekanisme akan sama atau serupa, sehingga kecepatan pencarian dan jejak memori mereka akan kurang lebih sama.

Melayani
sumber
1
@ JohnBustos Dalam hal kinerja, no. Ini murni logis. Anda dapat memberikan referensi ke struktur di sekitar yang tidak khawatir tentang orang lain yang memodifikasinya dari bawah Anda. Anda dapat membuat asumsi pada fakta bahwa tidak dapat diubah bahwa Anda tidak bisa jika itu bisa berubah.
Servy
Terima kasih, Servy, itu adalah poin yang sangat bagus ketika Anda sering melewati begitu banyak variabel ByRef - Setidaknya ini yang Anda yakin tidak dapat dimodifikasi. Terima kasih!
John Bustos
2
@JohnBustos Perlu diingat bahwa metode default untuk melewatkan parameter metode adalah berdasarkan nilai, Anda perlu menambahkan byref secara eksplisit, dan itu adalah sesuatu yang harus dilakukan dengan sangat jarang. Struktur data ini adalah kelas-kelas, yang membuatnya menjadi tipe referensi, jadi meneruskan nilainya adalah nilai referensi, itulah sebabnya meneruskannya ke metode lain dapat menyebabkan perubahan yang terlihat pada pemanggil.
Servy
Terima kasih, Servy, yang membuka kaleng cacing yang sama sekali baru untuk saya dalam hal apa yang telah saya lakukan :), tapi saya mengerti apa yang Anda katakan. Terima kasih!!
John Bustos
Di bawah selimut apakah Anda tahu jika Pencarian menggunakan hashbuckets untuk kunci?
paparazzo
10

Perbedaan lain yang belum disebutkan adalah bahwa Lookup () mendukung kunci null :

Kelas pencarian mengimplementasikan antarmuka ILookup. Pencarian sangat mirip dengan kamus kecuali beberapa nilai diizinkan untuk memetakan ke kunci yang sama, dan kunci nol didukung.

Noble_Bright_Life
sumber
4

Saat pengecualian bukan opsi, buka Pencarian

Jika Anda mencoba untuk mendapatkan struktur seefisien Dictionarytapi Anda tidak tahu pasti tidak ada kunci duplikat dalam input, Lookuplebih aman.

Seperti disebutkan dalam jawaban lain, itu juga mendukung kunci nol, dan mengembalikan selalu hasil yang valid ketika ditanyai dengan data yang sewenang-wenang, sehingga nampak lebih tangguh terhadap input yang tidak dikenal (kurang rentan daripada Kamus untuk meningkatkan pengecualian).

Dan itu benar terutama jika Anda membandingkannya dengan System.Linq.Enumerable.ToDictionaryfungsi:

// won't throw
new[] { 1, 1 }.ToLookup(x => x); 

// System.ArgumentException: An item with the same key has already been added.
new[] { 1, 1 }.ToDictionary(x => x);

Alternatifnya adalah menulis kode manajemen kunci duplikat Anda sendiri di dalam sebuah foreachloop.

Pertimbangan kinerja, Kamus: pemenang yang jelas

Jika Anda tidak memerlukan daftar dan Anda akan mengelola sejumlah besar item, Dictionary(atau bahkan struktur khusus Anda sendiri) akan lebih efisien:

        Stopwatch stopwatch = new Stopwatch();
        var list = new List<string>();
        for (int i = 0; i < 5000000; ++i)
        {
            list.Add(i.ToString());
        }
        stopwatch.Start();
        var lookup = list.ToLookup(x => x);
        stopwatch.Stop();
        Console.WriteLine("Creation: " + stopwatch.Elapsed);

        // ... Same but for ToDictionary
        var lookup = list.ToDictionary(x => x);
        // ...

Karena Lookupharus mempertahankan daftar item untuk setiap tombol, itu lebih lambat dari Kamus (sekitar 3x lebih lambat untuk sejumlah besar item)

Kecepatan pencarian: Penciptaan: 00: 00: 01.5760444

Kecepatan kamus: Pembuatan: 00: 00: 00.4418833

Hebat
sumber