Что происходит с поиском C # Dictionary <int, int>, если ключ не существует?

121

Я пробовал проверить значение null, но компилятор предупреждает, что этого условия никогда не будет. Что я должен искать?

deltanovember
источник

Ответы:

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, что верно, потому что он также должен извлекать ценность. Однако он не выполняет двух поисков.
Джон Скит,
Наивно, я все время ожидал null, но для Dictionary <TKey, enum> это возвращает эквивалент "0" в перечислении.
Джесс
23

Словарь выдает KeyNotFoundисключение в случае, если словарь не содержит вашего ключа.

Как предполагается, ContainsKeyэто соответствующая мера предосторожности. TryGetValueтакже эффективен.

Это позволяет словарю более эффективно хранить нулевое значение. Без такого поведения проверка на нулевой результат от оператора [] будет указывать либо на нулевое значение, либо на отсутствие входного ключа, что не годится.

антик
источник
Дополнительную информацию можно найти на MSDN: msdn.microsoft.com/en-gb/library/9tee9ht2.aspx
cyberzed
10

Если вы просто проверяете перед попыткой добавить новое значение, используйте ContainsKeyметод:

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

Если вы проверяете, существует ли значение, используйте TryGetValueметод, описанный в ответе Джона Скита.

ChrisF
источник
8
TryGet лучше
Рубен Бартелинк
2
Потому что вы дважды разрешаете поиск ключа через хеш-таблицу, если сразу после Get после Contains. Wintellect PowerCollections также имеет GetValueElseAddметоды, которым вы задаете значение (или Func<TValue>), чтобы также сохранить разрешение на Insert, если вы собираетесь добавить, если его там нет. Я предполагаю, что причина, по которой он не вошел в библиотеки .NET, заключается в том, что путь добавления используется реже, если вы используете его в стиле кеширования]
Рубен Бартелинк,
@rub: я думаю, это зависит от цели кода. Если вы хотите использовать значение, я согласен, что TryGetValueэто будет лучше, но если вы хотите проверить, содержит ли словарь ключ, чтобы избежать дублирующих добавлений, я бы сказал, что ContainsKeyэто так же хорошо (если не лучше).
Fredrik Mörk
@Fredrik: Если вы хотите только проверить условия содержания, то да, стоит использовать ContainsKey. Обратите внимание, что в примере кода этого ответа это не так.
Джон Скит,
@Jon: правда, я действительно пропустил, что добавленная стоимость была получена сразу после того, как она была добавлена.
Fredrik Mörk
3

Вы должны проверить Dictionary.ContainsKey (int key), прежде чем пытаться извлечь значение.

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
источник
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;
    }
}
Sheamus
источник
Иногда мне интересно, почему это не добавлено в стандартную библиотеку. Почти все языки, в которых используются хэш-карты, возвращают null, если нет записи, а это не чертовски исключение. Элемент, которого нет в вашем словаре, не является исключительным поведением.
Адам Хесс
@AdamHess - вот почему у вас есть Hashtable () в C # ... к сожалению, ваши ключи там
запакованы
0

Вероятно, вам следует использовать:

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

Причина, по которой вы не можете проверить значение null, заключается в том, что ключ здесь является типом значения.

Razzie
источник
1
Тип значения не имеет значения, так как проверка на null не даст желаемого эффекта.
Джон Скит,
@Johannes, решение Джона, конечно, лучше, но спрашивающий заявил, что он проверил, существует ли ключ, и это Dictionary <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;
    }
}

Затем вы можете управлять поведением этого словаря.

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

pablocom96
источник