Що трапиться з пошуком C # Dictionary <int, int>, якщо ключ не існує?


121

Я спробував перевірити нуль, але компілятор попереджає, що ця умова ніколи не відбудеться. Що я повинен шукати?

Відповіді:


196

Припускаючи , що ви хочете , щоб отримати значення , якщо ключ робить існує, використовуйте 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
}

(Використання, ContainsKeyа потім індексатор змушує шукати ключ двічі, що досить безглуздо.)

Зверніть увагу , що навіть якщо ви були з допомогою посилальних типів, перевірка на нуль не працюватиме - індексатор для Dictionary<,>згенерує виняток , якщо ви запитуєте відсутній ключ, а не повертати нуль. (Це велика різниця між Dictionary<,>і Hashtable.)


@JonSkeet Чи не TryGetValue також робить подвійний пошук ( як зазначено в цьому питанні )?
nawfal

5
@nawfal: Я не бачу жодних ознак того, що це питання взагалі говорить про це. Він говорить, що це робить більше роботи, ніж ContainsKey, що правда, тому що вона також повинна витягувати цінність. Але це не робить два пошуки.
Джон Скіт

Наївно я не очікував нуля, але для словника <TKey, enum> це повертає еквівалент "0" у перерахунку.
Джесс

23

Словник кидає KeyNotFoundвиняток в тому випадку, якщо словник не містить ключ.

Як пропонується, ContainsKeyє відповідною обережністю. TryGetValueтакож є ефективним.

Це дозволяє словнику ефективніше зберігати значення null. Без того, щоб він поводився таким чином, перевірка наявності нульового результату від оператора [] вказувала б або нульове значення АБО відсутність ключа введення, що не є корисним.


Додаткову інформацію можна знайти на веб-сторінці MSDN: msdn.microsoft.com/en-gb/library/9tee9ht2.aspx
закарбовано

10

Якщо ви просто перевіряєте, перш ніж намагатися додати нове значення, скористайтеся ContainsKeyметодом:

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

Якщо ви перевіряєте, чи існує значення, використовуйте TryGetValueметод, описаний у відповіді Джона Скіта.


8
TryGet краще
Рубен Бартелінк,

2
Тому що ви вирішите пошук ключів через хешблет двічі, якщо ви негайно отримаєте після "Містить". Wintellect PowerCollections також має GetValueElseAddметоди, яким ви даєте значення (або а Func<TValue>), щоб також зберегти роздільну здатність на Вставці, якщо ви збираєтесь додати, якщо її немає. Я здогадуюсь, що причина, чому він не потрапив у .NET libs, полягає в тому, що шлях додавання рідше, якщо ви використовуєте його в стилі кешу]
Рубен Бартелінк,

@rub: Я думаю, це залежить від мети коду. Якщо ви хочете використовувати значення, я погоджуюся, що TryGetValueбуло б краще, але якщо ви хочете перевірити, чи містить словник ключ, щоб уникнути повторюваних доповнень, я б сказав, що ContainsKeyце так само добре (якщо не краще).
Фредрік Мьорк

@Fredrik: Якщо ви хочете лише перевірити стримування, то так, варто використовувати ContainsKey. Зауважте, що це не так у зразковому коді цієї відповіді.
Джон Скіт

@Jon: правда, я насправді пропустив, що додана вартість була отримана одразу після її додавання.
Фредрік Морк

3

Ви повинні перевірити Dictionary.ContainsKey (клавіша int), перш ніж намагатися витягнути значення.

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.
}

2
Чому ви хочете змусити його робити пошук двічі?
Джон Скіт

2
@mookid: Не на мій погляд. Ідея полягає в тому, щоб спробувати знайти ключ і здійснити один курс дій, якщо він знайдений, а інший спосіб дії в іншому випадку, правда?
Джон Скіт

3
@Jon - Чесно? Тому що я не знав про це TryGetValue. На щастя, я це роблю зараз, тому знаю в майбутньому. Я залишаю цю відповідь недоторканою, хоча «дискусія цінна.
ZombieSheep

@Jon Skeet - Тому я тут. :)
ZombieSheep

@JonSkeet Тому що перед C # 7 ви не могли використовувати TryGetValueламбда-вираз. Хоча це і змушує мене думати, що нове розширення на C # буде catchоператором, подібним до оператора з’єднання null.
NetMage

1

Клас помічників зручний:

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;
    }
}

Іноді мені цікаво, чому це не додано до стандартної бібліотеки. Практично всі мови, які використовують хешмапи, повертають нуль, якщо немає запису, не вигадливий виняток. Елемент, який не існує у вашому словнику, не є винятковою поведінкою.
Адам Гесс

@AdamHess - ось чому у вас є Hashtable () в c # ..., на жаль, ваші ключі там знаходяться в коробці ... :(
veljkoz


0

Ймовірно, ви повинні використовувати:

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

Причина, по якій ви не можете перевірити нуль, полягає в тому, що ключ тут є типом значення.


1
Тип значення дещо не має значення, оскільки перевірка на нуль не мала б бажаного ефекту.
Джон Скіт

@Johannes, рішення Йона, звичайно, краще, але запитувач заявив, що перевірив, чи існує ключ, і це Словник <int, int>, тому ключ також є типом значення.
Razzie

0
int result= YourDictionaryName.TryGetValue(key, out int value) ? YourDictionaryName[key] : 0;

Якщо ключ присутній у словнику, він повертає значення ключа, інакше він повертає 0.

Сподіваюся, цей код вам допоможе.


1
Якщо ключ існує, цей код буде шукати двічі. TryGetValueдостатньо, використовуйте valueзамістьresult
Mathieu VIALES

0

Розглянемо варіант інкапсуляції цього конкретного словника та надамо метод повернення значення для цього ключа:

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;
    }
}

Тоді ви можете керувати поведінкою цього словника.

Наприклад тут: якщо в словнику немає ключа, він повертає ключ, який ви передаєте за параметром.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.