Dari entri MSDN di Dictionary.TryGetValue Method :
Metode ini menggabungkan fungsionalitas metode ContainsKey dan properti Item.
Jika kunci tidak ditemukan, maka parameter nilai mendapatkan nilai default yang sesuai untuk tipe nilai TValue; misalnya, 0 (nol) untuk tipe integer, false untuk tipe Boolean, dan null untuk tipe referensi.
Gunakan metode TryGetValue jika kode Anda sering mencoba mengakses kunci yang tidak ada dalam kamus. Menggunakan metode ini lebih efisien daripada menangkap KeyNotFoundException yang dilemparkan oleh properti Item.
Metode ini mendekati operasi O (1).
Dari deskripsi, tidak jelas apakah itu lebih efisien atau hanya lebih mudah daripada memanggil ContainsKey dan kemudian melakukan pencarian. Apakah implementasi TryGetValue
hanya memanggil ContainsKey dan kemudian Item atau sebenarnya lebih efisien dari itu dengan melakukan pencarian tunggal?
Dengan kata lain, apa yang lebih efisien (yaitu mana yang melakukan pencarian lebih sedikit):
Dictionary<int,int> dict;
//...//
int ival;
if(dict.ContainsKey(ikey))
{
ival = dict[ikey];
}
else
{
ival = default(int);
}
atau
Dictionary<int,int> dict;
//...//
int ival;
dict.TryGetValue(ikey, out ival);
Catatan: Saya tidak mencari patokan!
sumber
if(dict.ContainsKey(ikey)) dict[ikey]++; else dict.Add(ikey, 0);
. Tapi saya pikir ituTryGetValue
masih lebih efisien karena get dan set properti indexer digunakan, bukan?Patokan cepat menunjukkan bahwa
TryGetValue
memiliki sedikit keunggulan:Ini menghasilkan
membuat
ContainsKey + Item
akses sekitar 40% lebih lambat dengan asumsi paduan yang merata antara hit dan miss.Terlebih lagi, ketika saya mengubah program untuk selalu ketinggalan (yaitu selalu melihat ke atas
"b"
) kedua versi menjadi sama cepatnya:Namun, ketika saya menjadikannya "semua hit",
TryGetValue
sisanya tetap menjadi pemenang yang jelas:sumber
TryGetValue
harus jauh di depan. Juga ... nitpick ...DateTime
bukan cara terbaik untuk menangkap pengukuran kinerja.TryGetValue
semakin jauh ke depan. Saya mengedit jawaban untuk memasukkan skenario "semua hit" dan "semua ketinggalan".Any
- Seperti ini:Any(i=>i.Key==key)
. Dalam hal ini, ya, itu adalah pencarian linear kamus yang buruk.DateTime.Now
hanya akan akurat hingga beberapa ms. GunakanStopwatch
kelasSystem.Diagnostics
sebagai gantinya (yang menggunakan QueryPerformanceCounter di bawah selimut untuk memberikan akurasi yang jauh lebih tinggi). Lebih mudah digunakan juga.Karena sejauh ini tidak ada jawaban yang benar-benar menjawab pertanyaan, berikut adalah jawaban yang dapat diterima yang saya temukan setelah beberapa penelitian:
Jika Anda mendekompilasi TryGetValue Anda melihat itu melakukan ini:
sedangkan metode ContainsKey adalah:
jadi TryGetValue hanya ContainsKey plus pencarian array jika item ada.
Sumber
Tampaknya TryGetValue akan hampir dua kali lebih cepat dari kombinasi ContainsKey + Item.
sumber
Siapa peduli :-)
Anda mungkin bertanya karena sulit
TryGetValue
digunakan - jadi enkapsulasi seperti ini dengan metode ekstensi.Lalu panggil saja:
atau
sumber
this
tetapi ternyata saya memiliki metode saya digandakan dua kali di basis kode saya - sekali dengan dan satu tanpathis
jadi itu sebabnya saya tidak pernah menangkapnya! terima kasih sudah memperbaiki!TryGetValue
memberikan nilai default ke parameter nilai keluar jika kunci tidak ada, jadi ini bisa disederhanakan.if(!dic.TryGetValue(key, out value item)) item = dic[key] = new Item();
Mengapa Anda tidak mengujinya?
Tapi saya cukup yakin itu
TryGetValue
lebih cepat, karena hanya melakukan satu pencarian. Tentu saja ini tidak dijamin, yaitu implementasi yang berbeda mungkin memiliki karakteristik kinerja yang berbeda.Cara saya menerapkan kamus adalah dengan membuat
Find
fungsi internal yang menemukan slot untuk sebuah item, dan kemudian membangun sisanya di atasnya.sumber
Semua jawaban sejauh ini, meskipun bagus, kehilangan satu poin penting.
Metode ke dalam kelas API (misalnya .NET framework) membentuk bagian dari definisi antarmuka (bukan antarmuka C # atau VB, tetapi antarmuka dalam makna ilmu komputer).
Karena itu, biasanya tidak benar untuk bertanya apakah memanggil metode seperti itu lebih cepat, kecuali kecepatan adalah bagian dari definisi antarmuka formal (yang tidak dalam hal ini).
Secara tradisional cara pintas semacam ini (menggabungkan pencarian dan mengambil) lebih efisien terlepas dari bahasa, infrastruktur, OS, platform, atau arsitektur mesin. Ini juga lebih mudah dibaca, karena mengekspresikan maksud Anda secara eksplisit, daripada menyiratkannya (dari struktur kode Anda).
Jadi jawabannya (dari hack lama beruban) pasti 'Ya' (TryGetValue lebih disukai daripada kombinasi ContainsKey dan Item [Dapatkan] untuk mengambil nilai dari Kamus).
Jika Anda berpikir ini terdengar aneh, pikirkan seperti ini: Bahkan jika implementasi TryGetValue, ContainsKey, dan Item [Get] saat ini tidak menghasilkan perbedaan kecepatan, Anda dapat mengasumsikan bahwa kemungkinan implementasi di masa depan (mis. NET v5) akan melakukannya (TryGetValue akan lebih cepat). Pikirkan tentang masa pakai perangkat lunak Anda.
Sebagai tambahan, sangat menarik untuk dicatat bahwa tipikal teknologi definisi antarmuka modern masih jarang memberikan cara mendefinisikan batasan waktu secara formal. Mungkin .NET v5?
sumber
Membuat program pengujian cepat, pasti ada peningkatan menggunakan TryGetValue dengan 1 juta item dalam kamus.
Hasil:
ContainsKey + Item untuk 10.00000 hits: 45 ms
TryGetValue for 1000000 hits: 26ms
Ini adalah aplikasi tesnya:
sumber
Di mesin saya, dengan banyak RAM, ketika dijalankan dalam mode RELEASE (bukan DEBUG),
ContainsKey
sama denganTryGetValue
/try-catch
jika semua entri dalamDictionary<>
ditemukan.ContainsKey
mengungguli semuanya sejauh ini ketika hanya ada beberapa entri kamus yang tidak ditemukan (dalam contoh saya di bawah ini, aturMAXVAL
ke sesuatu yang lebih besar daripadaENTRIES
beberapa entri yang terlewat):Hasil:
Ini kode saya:
sumber
Selain merancang microbenchmark yang akan memberikan hasil yang akurat dalam pengaturan praktis, Anda dapat memeriksa sumber referensi .NET Framework.
System.Collections.Generic.Dictionary<TKey, TValue>.TryGetValue(TKey, out TValue)
System.Collections.Generic.Dictionary<TKey, TValue>.ContainsKey(TKey)
System.Collections.Generic.Dictionary<TKey, TValue>.Item(TKey)
Semua dari mereka memanggil
FindEntry(TKey)
metode yang melakukan sebagian besar pekerjaan dan tidak menghafal hasilnya, sehingga panggilanTryGetValue
hampir dua kali lebih cepat dariContainsKey
+Item
.Antarmuka yang tidak nyaman
TryGetValue
dapat diadaptasi menggunakan metode ekstensi :Karena C # 7.1, Anda dapat mengganti
default(TValue)
dengan yang biasadefault
. Jenisnya disimpulkan.Pemakaian:
Ini mengembalikan
null
untuk jenis referensi yang pencariannya gagal, kecuali nilai standar eksplisit ditentukan.sumber
Jika Anda mencoba untuk mendapatkan nilai dari kamus, TryGetValue (kunci, nilai keluar) adalah pilihan terbaik, tetapi jika Anda memeriksa keberadaan kunci, untuk penyisipan baru, tanpa menimpa kunci lama, dan hanya dengan ruang lingkup itu, ContainsKey (kunci) adalah pilihan terbaik, patokan dapat mengkonfirmasi ini:
Ini adalah Contoh yang benar, saya memiliki layanan yang untuk setiap "Item" yang dibuat, itu mengaitkan angka progresif, nomor ini, setiap kali Anda membuat item baru, harus ditemukan gratis, jika Anda menghapus Item, nomor bebas menjadi gratis, tentu saja ini tidak dioptimalkan, karena saya memiliki var statis yang menyimpan nomor saat ini, tetapi jika Anda mengakhiri semua angka, Anda dapat memulai kembali dari 0 hingga UInt32.MaxValue
Uji dieksekusi:
Menambahkan elemen ke
hashtabel ... Dilakukan di 0,5908 - jeda ....
Menambahkan elemen ke kamus ...
Selesai dalam 0,2679 - jeda ....
Menemukan nomor bebas pertama untuk penyisipan
Metode pertama : ContainsKey
Done in 0,0561 - nilai tambah 1000000 dalam kamus - jeda ....
Metode kedua: TryGetValue
Done in 0,0643 - nilai tambah 1000001 dalam kamus - jeda ....
Uji hashtable
Selesai dalam 0, 3015 - nilai tambah 1000000 ke dalam hashtable - pause ....
Tekan sembarang tombol untuk melanjutkan. .
Jika beberapa dari Anda mungkin bertanya apakah ContainsKeys dapat memiliki keuntungan, saya bahkan sudah mencoba membalikkan kunci TryGetValue with Contains, hasilnya sama.
Jadi, bagi saya, dengan pertimbangan akhir, semuanya tergantung pada cara program itu bertindak.
sumber