Различные способы добавления в словарь - PullRequest
89 голосов
/ 03 декабря 2009

Какая разница в Dictionary.add(key, value) и Dictionary[key] = value?

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

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

Ответы [ 7 ]

97 голосов
/ 03 декабря 2009

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

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

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

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

66 голосов
/ 03 декабря 2009

Первая версия добавит новую 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     
28 голосов
/ 03 декабря 2009

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

  • Используйте метод Add, чтобы добавить новую пару ключ / значение, существующие ключи не будут заменены (выброшено ArgumentException).
  • Используйте индексатор, если вам все равно, существует ли ключ в словаре, другими словами: добавьте пару ключ / значение, если ключа нет в словаре, или замените значение для указанного ключа, если ключ уже в словаре.
22 голосов
/ 09 декабря 2016

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

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 , затем вы ищите это значение в своем корзине, чтобы найти, есть ли оно там. Если это так, вы просто переписываете значение, назначенное клавише. Если его там нет, вы поместите свою ценность в корзину.

При вызове функции Add в вашем словаре, например:

myDietFavorite.Add(0, "Chocolate");

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

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

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

4 голосов
/ 03 декабря 2009

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

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

0 голосов
/ 31 декабря 2015

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

0 голосов
/ 03 декабря 2009

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

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

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

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