Подтвердить что ты не робот

.net словарь и поиск добавить/обновить

Мне больно делать блоки кода вроде этого для различных бит кода, которые у меня есть:

if (dict.ContainsKey[key]) {  
    dict[key] = value;  
}  
else {  
    dict.Add(key,value);  
}

и для поиска (т.е. ключ → список значений)

if (lookup.ContainsKey[key]) {  
    lookup[key].Add(value);  
}  
else {  
    lookup.Add(new List<valuetype>);  
    lookup[key].Add(value);  
}  

Есть ли другой сборник lib или метод расширения, который я должен использовать, чтобы сделать это в одной строке кода независимо от того, какие типы ключей и значений?

например.

dict.AddOrUpdate(key,value)  
lookup.AddOrUpdate(key,value)
4b9b3361

Ответ 1

Как говорит Евгений, индексатор уже заменит существующие значения - поэтому, если вы просто хотите безоговорочно установить значение для данного ключа, вы можете сделать

dictionary[key] = value;

Более интересным является "получить значение или вставить его при необходимости". Это легко сделать с помощью метода расширения:

public static TValue GetOrCreateValue<TKey, TValue>
    (this IDictionary<TKey, TValue> dictionary,
     TKey key,
     TValue value)
{
    return dictionary.GetOrCreateValue(key, () => value);
}

public static TValue GetOrCreateValue<TKey, TValue>
    (this IDictionary<TKey, TValue> dictionary,
     TKey key,
     Func<TValue> valueProvider)
{
    TValue ret;
    if (!dictionary.TryGetValue(key, out ret))
    {
        ret = valueProvider();
        dictionary[key] = ret;
    }
    return ret;
}

Обратите внимание на использование делегата для создания значения по умолчанию - что облегчает такие сценарии, как "список как значение"; вы не хотите создавать пустой список, если вам не нужно:

dict.GetOrCreateValue(key, () => new List<int>()).Add(item);

Также обратите внимание, как это выполняется только один раз, если ключ уже присутствует - нет необходимости делать ContainsKey, а затем искать значение. Тем не менее, при создании нового значения все еще требуется два поиска.

Ответ 2

При обновлении вам не нужно выполнять проверку. Просто используйте:

dict[key] = value

Он заменит любое существующее значение. При извлечении значения, к сожалению, нет удобного единого метода (например, setdefault в Python), но вы можете создать свой собственный метод расширения. Что-то вроде этого:

if (!lookup.TryGetValue(key, out value))
{
     value = new List<T>();
     lookup.Add(key, value);
}

Ответ 3

ConcurrentDictionary в .NET 4.0 этот хороший метод. Вы также можете написать для этого метод расширения.

Ответ 4

Если вы работаете с .NET Framework 4 или более поздней версией, вы можете использовать AddOrUpdate Method

dict.AddOrUpdate(key,value)  

добавить или обновить вот так

dict[key] = value;

Ответ 5

Я не уверен, есть ли такой метод, как вы просите, но вы можете написать для него небольшую функцию или использовать исключение catch catch, предположительно, если вы попробуете добавить уже существующее значение, оно вызовет исключение. Если вы поймаете это и проигнорируете его... Просто предложение

Ответ 6

Мне нравится AddOrUpdate метод ConcurrentDictionary, но я например, производительность словарейского сбора:) Итак, это метод расширения для всех классов, реализующих IDictionary.

public static TValue AddOrUpdate<TKey, TValue>(
    this IDictionary<TKey, TValue> dict,
    TKey key,
    TValue addValue,
    Func<TKey, TValue, TValue> updateValueFactory)
{
    TValue existing;
    if (dict.TryGetValue(key, out existing))
    {
        addValue = updateValueFactory(key, existing);
        dict[key] = addValue;
    }
    else
    {
        dict.Add(key, addValue);
    }

    return addValue;
}


public static TValue AddOrUpdate<TKey, TValue>(
    this IDictionary<TKey, TValue> dict,
    TKey key,
    Func<TKey, TValue> addValueFactory,
    Func<TKey, TValue, TValue> updateValueFactory)
{
    TValue existing;
    if (dict.TryGetValue(key, out existing))
    {
        existing = updateValueFactory(key, existing);
        dict[key] = existing;
    }
    else
    {
        existing = addValueFactory(key);
        dict.Add(key, existing);
    }

    return existing;
}