Различные способы добавления в словарь

108

В чем разница между Dictionary.add(key, value)и Dictionary[key] = value?

Я заметил, что последняя версия не выдает ошибку ArgumentExceptionпри вставке повторяющегося ключа, но есть ли причина предпочесть первую версию?

Изменить : есть ли у кого-нибудь авторитетный источник информации об этом? Я пробовал MSDN, но это, как всегда, погоня за дикими гусями :(

Сьюн Риверс
источник

Ответы:

110

Производительность почти на 100% идентична. Вы можете убедиться в этом, открыв класс в Reflector.net.

Это индексатор This:

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, он выдает исключение.

Так что для всех целей и намерений производительность одинакова.

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

Извините за длинный пост, надеюсь, все в порядке.

Steffen
источник
+1 Очень интересно, спасибо за пост! Казалось бы, производительность здесь почти такая же, как намекали другие плакаты, в любом случае отличная находка :)
Sune Rievers
70

Первая версия добавит в словарь новый 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     
hhravn
источник
+1 У вас есть источник вышеуказанной информации? Мне интересно узнать, есть ли какие-либо побочные эффекты или предостережения при использовании первой или последней формы.
Sune Rievers 03
3
На самом деле у меня нет источника как такового, просто в голове, но я не думаю, что в этом есть что-то большее, чем упомянуто в других комментариях. Если я правильно помню, Add просто использует индексатор, но сначала проверяет, используется ли уже ключ.
hhravn 03
1
Изменен принятый ответ Штеффена, потому что его документация на высшем уровне. Тем не менее, это отличный ответ.
Sune Rievers, 03
@Sune: Плохой ход ... лично я думаю, что этот ответ - улицы впереди Штеффена ... прямо к делу и достойный пример.
demoncodemonkey
1
@SuneRievers Я думаю, людям будет лучше, если на это будет принят ответ, а не текущий принятый ответ. Потому что это в точности отвечает на вопрос («в чем разница»), а не на принятый (который говорит о производительности, и почти 99% пользователей, ищущих эту тему (например, я), нуждаются в «различии» (почему я встретил это тема), и принятый ответ был бесполезен для меня и тратит впустую нашу секунду. Вместо этого, этот ответ точный.
T.Todua 07
30

Dictionary.Add(key, value)и Dictionary[key] = valueимеют разные цели:

  • Используйте этот Addметод для добавления новой пары ключ / значение, существующие ключи не будут заменены (выдается ArgumentExceptionсимвол).
  • Используйте индексатор, если вам все равно, существует ли уже ключ в словаре, другими словами: добавьте пару ключ / значение, если ключа нет в словаре, или замените значение для указанного ключа, если ключ уже есть в словаре.
Михаил Даматов
источник
1
Код, который самоописывает намерения, важен и чрезвычайно ценен (и практически не требует комментариев). Этот ответ показывает разницу в намерениях обоих методов, и его следует соблюдать при выборе одного из них. Другими словами, не используйте «indexer add», если вы заранее знаете, что всегда будете добавлять или даже должны всегда добавлять. Возникновение исключения IndexOutOfBounds лучше, чем неожиданное поведение.
ryancdotnet 07
28

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

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";

Но не забывайте, что вы программист, и с этого момента вы заканчиваете свои предложения словами: вы отказываетесь использовать смайлики, потому что они вызовут ошибку компиляции, а весь список избранного имеет индекс 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");

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

Метод Add позволяет вам добавить запись, но только при одном условии: ключ для этого определения может не существовать в вашем словаре.

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

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

myDietFavorites[0] = "Pizza";

В ведро идет db2dc565 "Пицца" (упрощенно).

Когда вы меняете значение с помощью:

myDietFavorites[0] = "Spaghetti";

Вы хешируете свой 0, который снова является db2dc565, затем вы просматриваете это значение в своем сегменте, чтобы узнать, есть ли оно там. Если это так, вы просто перезаписываете значение, присвоенное ключу. Если его там нет, вы поместите свою ценность в корзину.

Когда вы вызываете функцию добавления в своем словаре, например:

myDietFavorite.Add(0, "Chocolate");

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

Очень важно знать, как это работает, особенно если вы работаете со словарями с ключом строкового или символьного типа. Это чувствительно к регистру из-за хеширования. Так, например, «name»! = «Name». Давайте воспользуемся CRC32, чтобы изобразить это.

Значение для «name»: e04112b1 Значение для «Name»: 1107fb5b

Камил Куржиновски
источник
Этих двух строк достаточно, чтобы понять ....... Есть две возможности с определением: либо вы хотите дать новое определение для чего-то, чего раньше не существовало, либо вы хотите изменить определение, которое уже существует. Метод Add позволяет вам добавить запись, но только при одном условии: ключ для этого определения может не существовать в вашем словаре.
Нирадж Триведи
4

Да, в этом разница, метод Add выдает исключение, если ключ уже существует.

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

Гуффа
источник
0

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

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

dict[key] = valueПредставляет лучшую замену. Если я увижу этот код, я почти ожидаю, что ключ уже есть в словаре.

Хорхе Кордова
источник
Я предполагаю, что если сначала не проверять, существует ли ключ, есть небольшой выигрыш в производительности. Я не ожидал бы от , dic[key] = valueчто ключ уже присутствует, но я предполагаю , что спорно;)
Суна Rievers
2
+ я думаю, что бросание никогда не должно использоваться как способ проверки того, что ключ уже представлен. если (! strings.ContainsKey ("foo")) strings.Add ("foo", "bar");
hhravn 03
0

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

Джошуа Смит
источник
0

Чтобы вставить значение в словарь

 Dictionary<string, string> dDS1 = new Dictionary<string, string>();//Declaration
 dDS1.Add("VEqpt", "aaaa");//adding key and value into the dictionary
 string Count = dDS1["VEqpt"];//assigning the value of dictionary key to Count variable
 dDS1["VEqpt"] = Count + "bbbb";//assigning the value to key
Магхалакшми Саравана
источник