Saya memiliki item 60k yang perlu diperiksa dengan daftar pencarian 20k. Apakah ada objek koleksi (seperti List
, HashTable
) yang menyediakan metode yang sangat cepat Contains()
? Atau apakah saya harus menulis sendiri? Di kata lain, adalah Contains()
metode default hanya memindai setiap item atau apakah itu menggunakan algoritma pencarian yang lebih baik.
foreach (Record item in LargeCollection)
{
if (LookupCollection.Contains(item.Key))
{
// Do something
}
}
Catatan . Daftar pencarian sudah diurutkan.
c#
.net
search
collections
Ondrej Janacek
sumber
sumber
Jawaban:
Dalam kasus yang paling umum, pertimbangkan
System.Collections.Generic.HashSet
sebagai struktur data kuda kerja "Berisi" default Anda, karena memerlukan waktu yang konstan untuk mengevaluasiContains
.Jawaban aktual untuk "Apa koleksi tercepat yang bisa dicari" tergantung pada ukuran data spesifik Anda, keteraturan, biaya, dan frekuensi pencarian.
sumber
Jika Anda tidak perlu memesan, coba
HashSet<Record>
(baru ke .Net 3.5)Jika ya, gunakan a
List<Record>
dan panggilBinarySearch
.sumber
ImmutableSortedSet
dari System.ImmutableCollectionsSudahkah Anda mempertimbangkan
List.BinarySearch(item)
?Anda mengatakan bahwa koleksi besar Anda sudah diurutkan jadi ini sepertinya peluang yang sempurna? Hash pasti akan menjadi yang tercepat, tetapi ini membawa masalah sendiri dan membutuhkan lebih banyak overhead untuk penyimpanan.
sumber
Anda harus membaca blog ini yang menguji beberapa jenis koleksi dan metode untuk masing-masing menggunakan teknik tunggal dan multi-utas.
Menurut hasil, BinarySearch pada Daftar dan SortedList adalah berkinerja terbaik yang terus-menerus berjalan leher ketika mencari sesuatu sebagai "nilai".
Saat menggunakan koleksi yang memungkinkan untuk "kunci", Kamus, ConcurrentDictionary, Hashset, dan HashTables melakukan yang terbaik secara keseluruhan.
sumber
Simpan kedua daftar x dan y dalam urutan yang diurutkan.
Jika x = y, lakukan tindakan Anda, jika x <y, lanjut x, jika y <x, lanjutkan y hingga daftar kosong.
Run time dari persimpangan ini sebanding dengan min (ukuran (x), ukuran (y))
Jangan menjalankan loop .Contains (), ini sebanding dengan x * y yang jauh lebih buruk.
sumber
Jika mungkin untuk mengurutkan item Anda maka ada cara yang jauh lebih cepat untuk melakukan ini kemudian melakukan pencarian kunci ke dalam hashtable atau b-tree. Meskipun jika item Anda tidak dapat diurutkan, Anda tidak bisa memasukkannya ke dalam b-tree.
Ngomong-ngomong, jika sortir urutkan kedua daftar maka tinggal mengurutkan daftar pencarian secara berurutan.
sumber
Jika Anda menggunakan .Net 3.5, Anda dapat membuat kode yang lebih bersih menggunakan:
Saya tidak punya. Net 3.5 di sini dan ini belum teruji. Itu bergantung pada metode ekstensi. Bukan itu
LookupCollection.Intersect(LargeCollection)
mungkin tidak sama denganLargeCollection.Intersect(LookupCollection)
... yang terakhir mungkin jauh lebih lambat.Ini mengasumsikan LookupCollection adalah a
HashSet
sumber
Jika Anda tidak khawatir tentang mencicit setiap bit kinerja, saran untuk menggunakan HashSet atau pencarian biner adalah solid. Kumpulan data Anda tidak cukup besar sehingga ini akan menjadi masalah 99% dari waktu.
Tetapi jika ini hanya satu dari ribuan kali Anda akan melakukan ini dan kinerjanya sangat penting (dan terbukti tidak dapat diterima menggunakan HashSet / pencarian biner), Anda tentu bisa menulis algoritma Anda sendiri yang berjalan di daftar yang diurutkan melakukan perbandingan saat Anda pergi. Setiap daftar akan berjalan paling banyak sekali dan dalam kasus-kasus patologis tidak akan buruk (begitu Anda pergi rute ini Anda mungkin akan menemukan bahwa perbandingan, dengan asumsi itu adalah string atau nilai non-integral lainnya, akan menjadi biaya riil dan mengoptimalkan itu akan menjadi langkah berikutnya).
sumber