Apa yang terjadi pada pencarian C # Dictionary <int, int> jika kuncinya tidak ada?

121

Saya mencoba memeriksa null tetapi kompilator memperingatkan bahwa kondisi ini tidak akan pernah terjadi. Apa yang harus saya cari?

deltanovember.dll
sumber

Jawaban:

196

Dengan asumsi Anda ingin mendapatkan nilai jika kunci tidak ada, gunakan Dictionary<TKey, TValue>.TryGetValue:

int value;
if (dictionary.TryGetValue(key, out value))
{
    // Key was in dictionary; "value" contains corresponding value
} 
else 
{
    // Key wasn't in dictionary; "value" is now 0
}

(Menggunakan ContainsKeydan kemudian pengindeks membuatnya mencari kunci dua kali, yang tidak ada gunanya.)

Perhatikan bahwa bahkan jika Anda sedang menggunakan referensi jenis, memeriksa nol tidak akan bekerja - pengindeks untuk Dictionary<,>akan melemparkan pengecualian jika Anda meminta kunci hilang, daripada kembali nol. (Ini adalah perbedaan besar antara Dictionary<,>dan Hashtable.)

Jon Skeet
sumber
@JonSkeet Bukankah TryGetValue juga melakukan pencarian ganda ( seperti yang dinyatakan dalam badan pertanyaan ini )?
nawfal
5
@nawfal: Saya tidak melihat indikasi bahwa pertanyaan itu menyatakan hal itu sama sekali. Dikatakan melakukan lebih banyak pekerjaan daripada ContainsKey, yang benar, karena harus mengekstrak nilainya juga. Ini tidak melakukan dua pencarian.
Jon Skeet
Secara naif, saya terus mengharapkan null, tetapi untuk Dictionary <TKey, enum>, ini mengembalikan padanan "0" dalam enum.
Jess
23

Kamus melontarkan KeyNotFoundpengecualian jika kamus tidak berisi kunci Anda.

Seperti yang disarankan, ContainsKeyadalah tindakan pencegahan yang tepat. TryGetValuejuga efektif.

Ini memungkinkan kamus menyimpan nilai null dengan lebih efektif. Tanpa itu berperilaku seperti ini, memeriksa hasil null dari operator [] akan menunjukkan baik nilai null ATAU tidak adanya kunci input yang tidak baik.

antik
sumber
Informasi tambahan dapat ditemukan di MSDN: msdn.microsoft.com/en-gb/library/9tee9ht2.aspx
cyberzed
10

Jika Anda hanya memeriksa sebelum mencoba menambahkan nilai baru, gunakan ContainsKeymetode:

if (!openWith.ContainsKey("ht"))
{
    openWith.Add("ht", "hypertrm.exe");
}

Jika Anda memeriksa bahwa nilainya ada, gunakan TryGetValuemetode seperti yang dijelaskan dalam jawaban Jon Skeet.

ChrisF
sumber
8
TryGet lebih baik
Ruben Bartelink
2
Karena Anda menyelesaikan pencarian kunci melalui hashtable dua kali jika Anda segera Dapatkan setelah Mengandung. Wintellect PowerCollections juga memiliki GetValueElseAddmetode yang Anda beri nilai (atau a Func<TValue>) untuk juga menyimpan resolusi pada Sisipan jika Anda akan menambahkannya jika tidak ada. Saya kira alasan mengapa belum berhasil masuk ke libs .NET adalah karena jalur Tambah lebih jarang jika Anda menggunakannya dalam gaya cache]
Ruben Bartelink
@ Rub: Saya rasa itu tergantung pada tujuan kode. Jika Anda ingin menggunakan nilai saya setuju itu TryGetValueakan lebih baik, tetapi jika Anda ingin memeriksa apakah kamus berisi kunci untuk menghindari penambahan duplikat, saya akan mengatakan ContainsKeysama baiknya (jika tidak lebih baik).
Fredrik Mörk
@Fredrik: Jika Anda hanya ingin melakukan pemeriksaan penahanan, maka ya, ada baiknya menggunakan ContainsKey. Perhatikan bahwa tidak demikian halnya dalam kode sampel jawaban ini.
Jon Skeet
@ Jon: benar, saya sebenarnya melewatkan bahwa nilai tambah diambil segera setelah ditambahkan.
Fredrik Mörk
3

Anda harus memeriksa Dictionary.ContainsKey (kunci int) sebelum mencoba menarik nilainya.

Dictionary<int, int> myDictionary = new Dictionary<int, int>();
myDictionary.Add(2,4);
myDictionary.Add(3,5);

int keyToFind = 7;
if(myDictionary.ContainsKey(keyToFind))
{
    myValueLookup = myDictionay[keyToFind];
    // do work...
}
else
{
    // the key doesn't exist.
}
ZombieSheep
sumber
2
Mengapa Anda ingin membuatnya melakukan pencarian dua kali?
Jon Skeet
2
@mookid: Tidak menurut saya. Idenya adalah mencoba mencari kuncinya, dan mengambil satu tindakan jika ditemukan, dan tindakan lain jika tidak, bukan?
Jon Skeet
3
@ Jon - Jujur? Karena saya tidak tahu tentang TryGetValue. Syukurlah, saya melakukannya sekarang, jadi saya akan tahu di masa depan. Saya akan membiarkan jawaban ini utuh, meskipun diskusi karena itu berharga.
ZombieSheep
@ Jon Skeet - Itu sebabnya saya di sini. :)
ZombieSheep
@JonSkeet Karena sebelum C # 7, Anda tidak dapat menggunakan TryGetValueekspresi lambda. Meskipun itu membuat saya berpikir ekstensi baru untuk C # akan menjadi catchoperator yang mirip dengan nulloperator penggabungan.
NetMage
1

Kelas helper berguna:

public static class DictionaryHelper
{
    public static TVal Get<TKey, TVal>(this Dictionary<TKey, TVal> dictionary, TKey key, TVal defaultVal = default(TVal))
    {
        TVal val;
        if( dictionary.TryGetValue(key, out val) )
        {
            return val;
        }
        return defaultVal;
    }
}
Sheamus
sumber
Terkadang saya bertanya-tanya mengapa ini tidak ditambahkan ke pustaka standar. Hampir semua bahasa yang menggunakan hashmaps mengembalikan null jika tidak ada entri, bukan pengecualian. Item yang tidak ada dalam kamus Anda bukanlah perilaku luar biasa.
Adam Hess
@AdamHess - itulah mengapa Anda memiliki Hashtable () di c # ... sayangnya, kunci Anda
disimpan di
0

ContainsKey adalah apa yang Anda cari.


sumber
0

Anda mungkin harus menggunakan:

if(myDictionary.ContainsKey(someInt))
{
  // do something
}

Alasan mengapa Anda tidak dapat memeriksa null adalah karena kuncinya di sini adalah tipe nilai.

Razzie
sumber
1
Jenis nilainya agak tidak relevan, karena memeriksa null tidak akan memberikan efek yang diinginkan.
Jon Skeet
@Johannes, solusi Jon tentu saja jauh lebih baik, tetapi penanya menyatakan bahwa dia memeriksa apakah kuncinya ada, dan itu adalah Dictionary <int, int>, jadi kuncinya juga merupakan tipe nilai di sini.
Razzie
0
int result= YourDictionaryName.TryGetValue(key, out int value) ? YourDictionaryName[key] : 0;

Jika kunci ada dalam kamus, ia mengembalikan nilai kunci jika tidak ia mengembalikan 0.

Semoga kode ini membantu Anda.

Nitika Chopra
sumber
1
Jika kuncinya ada, kode ini akan mencari dua kali. TryGetValuesudah cukup, gunakan valuesebagai penggantiresult
Mathieu VIALES
0

Pertimbangkan opsi untuk mengenkapsulasi kamus khusus ini dan berikan metode untuk mengembalikan nilai untuk kunci itu:

public static class NumbersAdapter
{
    private static readonly Dictionary<string, string> Mapping = new Dictionary<string, string>
    {
        ["1"] = "One",
        ["2"] = "Two",
        ["3"] = "Three"
    };

    public static string GetValue(string key)
    {
        return Mapping.ContainsKey(key) ? Mapping[key] : key;
    }
}

Kemudian Anda dapat mengatur perilaku kamus ini.

Misalnya di sini: jika kamus tidak memiliki kunci, ia mengembalikan kunci yang Anda berikan parameter.

pablocom96
sumber