Различные способы добавления в словарь
какая разница в Dictionary.add(key, value)
и Dictionary[key] = value
?
Я заметил, что последняя версия не бросает ArgumentException
при вставке дубликата ключа, но есть ли причина предпочесть первую версию?
Edit: кто-нибудь авторитетный источник информации об этом? Я пробовал MSDN, но это, как всегда, дикая погоня за гусем: (
7 ответов:
производительность почти на 100% идентичны. Вы можете проверить это, открыв класс в Reflector.net
Это этот индексатор:
public TValue this[TKey key] { get { int index = this.FindEntry(key); if (index >= 0) { return this.entries[index].value; } ThrowHelper.ThrowKeyNotFoundException(); return default(TValue); } set { this.Insert(key, value, false); } }
и это метод Add:
public void Add(TKey key, TValue value) { this.Insert(key, value, true); }
Я не буду публиковать весь метод Insert, поскольку он довольно длинный, однако объявление метода таково:
private void Insert(TKey key, TValue value, bool add)
и далее вниз в функции, это происходит:
if ((this.entries[i].hashCode == num) && this.comparer.Equals(this.entries[i].key, key)) { if (add) { ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_AddingDuplicate); }
, который проверяет, если ключ уже существует, и если это произойдет и параметр add имеет значение true, он выдает исключение.
таким образом, для всех целей и намерений производительность одинакова.
как и несколько других упоминаний, все дело в том, нужна ли вам проверка, для попыток добавления одного и того же ключа дважды.
извините за длинный пост, я надеюсь, что все в порядке.
первая версия добавит новую KeyValuePair в словарь, бросая, если ключ уже находится в словаре. Второй, используя индексатор, добавит новую пару, если ключ не существует, но перезапишет значение ключа, если оно уже существует в словаре.
IDictionary<string, string> strings = new Dictionary<string, string>(); strings["foo"] = "bar"; //strings["foo"] == "bar" strings["foo"] = string.Empty; //strings["foo"] == string.empty strings.Add("foo", "bar"); //throws
Dictionary.Add(key, value)
иDictionary[key] = value
разные цели:
- использовать
Add
метод добавить новая пара ключ / значение, существующие ключи не будут заменены (anArgumentException
выбрасывается).- используйте индексатор, если вам все равно, существует ли ключ уже в словаре, другими словами: добавьте пару ключ/значение, если ключ не находится в словаре, или замените значение для указанного ключа, если ключ уже находится в словаре.
чтобы ответить на этот вопрос, сначала нам нужно взглянуть на цель словаря и лежащую в его основе технологию.
Dictionary
списокKeyValuePair<Tkey, Tvalue>
где каждое значение представлено своим уникальным ключом. Допустим, у нас есть список ваших любимых продуктов. Каждое значение (название еды) представлено своим уникальным ключом (позиция = насколько вам нравится эта еда).пример кода:
Dictionary<int, string> myDietFavorites = new Dictionary<int, string>() { { 1, "Burger"}, { 2, "Fries"}, { 3, "Donuts"} };
допустим, вы хотите оставаться здоровым, вы передумали и вы хотите заменить свой любимый "бургер" салатом. Ваш список по-прежнему является списком избранных, вы не будете изменять характер списка. Ваш любимый останется номером один в списке, только его значение изменится. Это когда вы называете это:
/*your key stays 1, you only replace the value assigned to this key you alter existing record in your dictionary*/ myDietFavorites[1] = "Salad";
но не забывайте, что вы программист, и с этого момента вы заканчиваете свои предложения ; вы отказываетесь использовать emojis, потому что они будут бросать ошибку компиляции, и весь список избранных основан на индексе 0.
ваш диета тоже изменилась! Поэтому вы снова изменяете свой список:
/*you don't want to replace Salad, you want to add this new fancy 0 position to your list. It wasn't there before so you can either define it*/ myDietFavorites[0] = "Pizza"; /*or Add it*/ myDietFavorites.Add(0, "Pizza");
есть две возможности с определением, вы либо хотите дать новое определение для чего-то не существующего раньше, либо вы хотите изменить определение, которое уже существует.
добавить метод позволяет добавить запись, но только при одном условии: ключ для этого определения может не существовать в вашем словаре.
теперь мы будем смотреть под капотом. Когда вы делаете словарь ваш компилятор сделайте резервацию для ведра (пробелы в памяти для хранения записей). Ведро не хранит ключи так, как вы их определяете. Каждый ключ хэшируется перед переходом к ведру (определенному Microsoft), стоит упомянуть, что часть значения остается неизменной.
Я буду использовать алгоритм хеширования CRC32 для упрощения моего примера. Когда вы определяете:
myDietFavorites[0] = "Pizza";
что идет в ведро это db2dc565 "пицца" (упрощенный).
при изменении значения в с:
myDietFavorites[0] = "Spaghetti";
вы хэш ваш 0, который снова db2dc565 затем вы смотрите это значение в вашем ведре, чтобы найти, если он там. Если он есть, вы просто переписываете значение, присвоенное ключу. Если его там нет, вы поместите свою ценность в ведро.
при вызове функции Add в вашем словаре, например:
myDietFavorite.Add(0, "Chocolate");
вы хешируете свой 0, чтобы сравнить его значение с теми, что в ведре. Вы можете поместить его в ведро только если это не там.
очень важно знать, как это работает, особенно если вы работаете со словарями типа string или char ключа. Это чувствительно к регистру из-за прохождения хэширования. Так, например, "имя" != "Имя." Давайте использовать наш CRC32, чтобы изобразить это.
значение "имя": e04112b1 Значение параметра "Name": 1107fb5b
Да, это разница, метод Add вызывает исключение, если ключ уже существует.
причина использования метода Add именно в этом. Если словарь не должен содержать ключ уже, вы обычно хотите исключение, чтобы вы знали о проблеме.
учитывая наиболее вероятные сходства в производительности, используйте все, что кажется более правильным и читаемым для части кода, который вы используете.
Я чувствую, что операция, которая описывает добавление, будучи наличие ключа уже действительно редкое исключение лучше всего представлены с add. Семантически это имеет больше смысла.
на
dict[key] = value
представляет собой лучшую замену. Если я вижу этот код, я наполовину ожидаю, что ключ уже будет в словаре в любом случае.