Автоматически создавая набор в Словаре <Ключ, Набор <Значение>>

Партия времен я должен создать a Dictionary<KeyType, List<ValueType>>

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

//Can i remove these two lines?
if(!dict.ContainsKey(key)) 
    dict[key]= new List<ValueType>;

//now use the key
dict[key].Add(value);

Я знаю его единственное "2 строки" кода, но он раздражает меня, и я думаю, что он может быть удален.

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

В основном я хочу создать a Dictionary<KeyType, Collection<ValueType>> и начните использовать его сразу же как dict[key].Add(value).

7
задан chikak 29 January 2010 в 07:01
поделиться

4 ответа

Вы можете создать что-то вроде Multimap из Google Java Collection ... или просто добавить такой метод расширения:

public static void AddValue<TKey, TValue>
    (this IDictionary<TKey, List<TValue>> dictionary, TKey key, TValue value)
{
    List<TValue> values;
    if (!dictionary.TryGetValue(key, out values))
    {
        values = new List<TValue>();
        dictionary.Add(key, values);
    }
    values.Add(value);
}

Как говорит Беван, Lookup также может помочь, но вы можете создать его только с помощью метода ToLookup , и вы не можете его изменить после этого. Во многих случаях это очень хорошо, но если вам нужна изменяемая карта, вам понадобится что-то вроде приведенного выше.

7
ответ дан 6 December 2019 в 21:13
поделиться

Чтобы добавить к ответам, вы также можете добавить более общее расширение, которое принимает делегат для инстанции:

public static TValue GetOrCreate<TKey, TValue>
    (this IDictionary<TKey, TValue> dict, 
          TKey key, 
          Func<TKey, TValue> getValue)
{
    TValue value;
    if (!dict.TryGetValue(key, out value))
    {
        dict.Add(key, getValue(key));
    }
    return value;
}

, а затем вы можете предоставить любой метод создания реализации:

Dictionary<int, string> dict = new Dictionary<int, string>();
string result = dict.GetOrCreate(5, i => i.ToString());
1
ответ дан 6 December 2019 в 21:13
поделиться

Способ CONCURRENTDICTICE .getoradd метод удивительно полезен.

private ConcurrentDictionary<string, ICollection<int>> _dictionary;

private static ICollection<int> CreateEmptyList(string dummyKey)
{
    return new List<int>();
}

private void AddValue(string key, int value)
{
    ICollection<int> values = _dictionary.GetOrAdd(key, CreateEmptyList);
    values.Add(value);
}

Редактировать: вот пример того, как реализовать функцию в качестве метода расширения для Iделиц (C # 3):

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

public static TValue GetOrAdd<TKey, TValue>(
    this IDictionary<TKey, TValue> dictionary,
    TKey key,
    Func<TKey, TValue> valueFactory)
{
    TValue value;
    if (!dictionary.TryGetValue(key, out value))
    {
        value = valueFactory(key);
        dictionary.Add(key, value);
    }

    return value;
}
2
ответ дан 6 December 2019 в 21:13
поделиться

Взгляните на LookUp класс, введенный с Linq в .NET 3.5 - это может быть именно то, что вы ищете: Словарь, подобный классу, который поддерживает несколько элементов на ключ.

Возможно, единственным существенным недостатком является то, что все ваши элементы должны быть доступны в одном пакете, так как LookUp является неизменным.

2
ответ дан 6 December 2019 в 21:13
поделиться
Другие вопросы по тегам:

Похожие вопросы: