2017-01-22 3 views
0

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

Со словарями, если я хочу добавить новый элемент, если ключ существует, он выбрасывает и исключает. На данный момент я всегда делаю что:

Dictionary<long, List<string>> myDic = new Dictionary<long, List<string>>(); 
long myNewKey = 1; 
if(myDic.ConatainsKey(1) == false) 
{ 
    myDic.Add(1, new List<string>()); 
} 
myDic[myNewKey].Add("string01"); 
myDic[myNewKey].Add("string02"); 

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

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

+0

Я думаю, что метод расширения лучший выбор здесь.
См. Также
http://stackoverflow.com/questions/11027369/how-to-correctly-handle-adding-new-item-to-dictionary – Piotshe

+0

более общий пример расширения здесь http://stackoverflow.com/questions/3850930/многозначный-словарь/41305901 # 41305901 – Slai

ответ

2

Зависит от типа значения словаря (как в значении ключа). В вашем примере с длинным ключом, указывающим на список строк, реальной проблемой является необходимость создания нового значения объекта. Если Словарь был типом значения (как в значении по сравнению с типом ссылки), указывающим на тип значения (например: long-> long), вы можете просто использовать индекс '[x]'. Если вы знаете диапазон ключей, вы можете заранее инициализировать свои объекты значений. Если вы просто пытаетесь уменьшить код, вы можете использовать метод расширения для объединения проверки, добавления объекта и установки. Что-то вроде этого:

public static class Extensions { 
    public static void AppendToValues(this Dictionary<long, List<string>> dict, long key, string str){ 
     if (dict.ContainsKey(key)) { 
      dict.Add(key, new List<string>()); 
      } 
     dict[key].Add(str); 
     } 
    } 

Затем в коде называют это так:

myDic.AppendToValues(myNewKey, "string01"); 
0

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

Вы можете найти хорошую реализацию метода расширения с использованием Dictionary.TryGetValue (который не выбрасывает исключение, если ключ не найден) здесь:

Dictionary returning a default value if the key does not exist

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

Dictionary<long, List<string>> myDic = new Dictionary<long, List<string>>(); 
long myNewKey = 1; 
List<string> list; 
if (!myDic.TryGetValue(myNewKey, out list)) 
{ 
    list = new List<string>(); 
    myDic.Add(myNewKey, list); 
} 

list.Add("string01"); 
list.Add("string02"); 
1

Dictionary<TKey,TValue> имеет два различных способа добавления элемента.

void Add(TKey key, TValue value): Потому что вы вызываете Add семантику, которую вы говорите, «это нет, заставьте ее присутствовать». Таким образом, исключение возникает при дублировании вставки, потому что оно не знает, хотите ли вы старое или новое.

Индексатор (TValue this[TKey key]) поддерживает назначение, в котором есть семантика «Я хочу, чтобы это было ответом, если я вызываю гейтер индексатора».

dict.Add(1, 1); 
var x = dict[1]; // x == 1 
dict.Add(1, 2); // throws 

dict.Add(1, 1); 
var x = dict[1]; // x == 1; 
dict[1] = 2; 
var y = dict[1]; // x == 1, y == 2. 

var dict = new Dictionary<long, int>(); 
dict[1] = 35; 
var x = dict[1]; // x == 35; 

ContainsKey почти всегда не то, что нужно позвонить. Если вы спокойно читаете значение, вызовите TryGetValue, и если вы просто хотите использовать словарь для хранения того, было ли что-то сделано, используйте HashSet<T>. (Whose Add метод возвращает a bool (true, если добавлено что-то добавлено (его не было), false, если Add did no work (значение уже существует))).

В вашем конкретном случае, когда вы хотите добавить вещи в список, подход TryGetValue является лучшим. Или, используя ConcurrentDictionary:

TryGetValue:

List<string> list; 

// Read the dictionary exactly once 
if (!dict.TryGetValue(key, out list)) 
{ 
    list = new List<string>(); 
    // Write at most once. 
    dict[key] = list; 
} 

list.Add(value); 

ConcurrentDictionary:

ConcurrentDictionary<long, List<string>> dict = new ConcurrentDictionary<long, List<string>>(); 
... 
List<string> list = dict.GetOrAdd(key,() => new List<string>()); 
list.Add(value); 
Смежные вопросы