Різні способи додавання до словника


107

У чому різниця в Dictionary.add(key, value)і Dictionary[key] = value?

Я помітив, що остання версія не кидає а, ArgumentExceptionколи вставляє дублікат ключа, але чи є причина віддати перевагу першій версії?

Редагувати : чи є у когось авторитетне джерело інформації про це? Я спробував MSDN, але це як завжди переслідування за дикими гусками :(

Відповіді:


109

Виконання майже на 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);
    }

Що перевіряє, чи ключ вже існує, і якщо він є, і додавання параметра є істинним, він викидає виняток.

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

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

Вибачте за довгий пост, сподіваюся, що це нормально.


+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     

+1 Чи отримали ви джерело для вищевказаної інформації? Мені цікаво дізнатися, чи є які-небудь побічні ефекти або застереження при використанні першої або другої форми.
Sune Rievers

3
У нас насправді немає джерела, як раз у верхній частині моєї голови, але я не думаю, що в ньому є набагато більше, ніж згадувалося в інших коментарях. Якщо я пам'ятаю правильно, Add просто використовує індексатор, але спочатку перевіряє, чи не використовується ключ.
hhravn

1
Змінено прийняту відповідь Стеффенса, оскільки його документація є першочерговою. Це все ще чудова відповідь.
Sune Rievers

@Sune: Поганий хід ... особисто я думаю, що ця відповідь - це вулиці попереду Стеффен ... прямо до суті і гідний приклад.
demoncodemonkey

1
@SuneRievers Я думаю, це буде більш корисним для людей, якщо за це приймуть відповідь, замість поточної прийнятої відповіді. Тому що це точно відповідає на питання ("яка різниця"), а не прийняте (що говорить про ефективність, і майже 99% користувачів, які шукають цю тему (як я), потребували "різниці" (чому я це зустрів тема), і прийнята відповідь виявилася для мене марною і марнує нашу другу. Натомість ця відповідь точна.
Т.Тодуа

30

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

  • Використовуйте Addметод для додавання нової пари ключ / значення, існуючі ключі не будуть замінені ( ArgumentExceptionкинуто).
  • Використовуйте індексатор, якщо вам не важливо, чи ключ вже існує у словнику, іншими словами: додайте пару ключ / значення, якщо ключа немає у словнику, або замініть значення вказаного ключа, якщо ключ вже є у словнику.

1
Код, який самостійно описує наміри, важливий і надзвичайно цінний (і вимагає мало-мало коментарів). Ця відповідь показує різницю у намірах обох методів, і слід дотримуватися її при виборі. Іншими словами, не використовуйте "додавання індексатора", коли ви заздалегідь знаєте, що ви завжди додаватимете або навіть завжди повинні додавати. Надання виключення IndexOutOfBounds краще, ніж несподівана поведінка.
ryancdotnet

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

Існує дві можливості з визначенням: ви або хочете дати нове визначення для чогось, що не існувало раніше, або ви хочете змінити визначення, яке вже існує.

Метод Додати дозволяє додавати запис, але лише за однієї умови: ключ для цього визначення може не існувати у вашому словнику.

Тепер ми будемо дивитись під капот. Коли ви створюєте словник, ваш компілятор зарезервує відро (пробіли в пам'яті для зберігання ваших записів). Відро не зберігає ключі так, як ви їх визначаєте. Кожен ключ хеширується перед тим, як перейти до відра (визначено Microsoft), варто згадати, що частина значення залишається незмінною.

Я буду використовувати алгоритм хешування CRC32 для спрощення мого прикладу. Коли ви визначаєте:

myDietFavorites[0] = "Pizza";

Що йде у відро, це db2dc565 "Піца" (спрощено).

Коли ви змінюєте значення на:

myDietFavorites[0] = "Spaghetti";

У вас є х 0, який знову-таки db2dc565 тоді ви шукаєте це значення у своєму відрі, щоб дізнатися, чи є він. Якщо він там, ви просто перепишіть значення, присвоєне ключу. Якщо його немає, ви помістіть свою вартість у відро.

Коли ви викликаєте функцію Додати у словнику, наприклад:

myDietFavorite.Add(0, "Chocolate");

У вас є х 0, щоб порівняти його з значенням у відрі. Ви можете помістити його у відро, лише якщо його немає .

Важливо знати, як це працює, особливо якщо ви працюєте зі словниками рядка чи знаку типу ключа. Це чутливе до регістру через перенесення хешування. Так, наприклад, "ім'я"! = "Ім'я". Давайте використаємо наш CRC32, щоб зобразити це.

Значення для "name" становить: e04112b1 Значення для "Name" дорівнює: 1107fb5b


Цього двох рядків достатньо, щоб зрозуміти ....... Є дві можливості з визначенням, ви або хочете дати нове визначення для чогось, що не існувало раніше, або ви хочете змінити визначення, яке вже існує. Метод Додати дозволяє додавати запис, але лише за однієї умови: ключ для цього визначення може не існувати у вашому словнику.
Нірай Тріведі

4

Так, це різниця, метод Add викидає виняток, якщо ключ вже існує.

Причина використання методу Add саме в цьому. Якщо словник не повинен містити ключ вже, ви хочете, щоб виняток був таким, щоб ви усвідомлювали проблему.


0

Враховуючи найбільш схожість у продуктивності, використовуйте будь-які правильніші та зручніші для читання фрагменти коду, якими ви користуєтесь.

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

Представляє dict[key] = valueсобою кращу заміну. Якщо я бачу цей код, я все одно очікую, що ключ вже буде у словнику.


Я б припустив, що невеликий приріст продуктивності, якщо не перевірити, чи існує ключ першим. Я не очікував би від dic[key] = valueцього ключа вже присутній, але я думаю, що це дискусійно;)
Sune Rievers

2
+ Я думаю, що метання ніколи не слід використовувати як спосіб перевірки, чи ключ уже представлений. if (! strings.ContainsKey ("foo")) strings.Add ("foo", "bar");
hhravn


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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.