Словник проти списку


30

Тому я натрапив на роботу Dictionary<int, int>сьогодні. Це мені здавалося дивним, тому що я, мабуть, просто використав би List<int>замість цього. Чи є різниця і чи не буде випадку використання, коли одна структура буде віддана перевагу іншій?


1
Чи має бути співвідношення між двома (або більше) заданими входами? Тоді карта (словник цією мовою) має сенс.
Ріг

3
Словник імен робить для мене очевидним. Коли вам потрібно щось швидко пошукати, ви використовуєте словник.
ChaosPandion

2
@ChaosPandion: a List<T>в рамках .NET - це масив випадкового доступу, де операція пошуку зазвичай швидша, ніж для Dictionary<int,T>.
Док Браун

2
@DocBrown - Тільки у досить дивному випадку використання числового індексу як ключа. Інші мудрі погляди вгору стануть швидшими при використанні Dictionary<TKey, TValue>.
ChaosPandion

2
@chaos це питання стосується тієї дивної справи.
MarkJ

Відповіді:


32

Ви б використовували, Dictionary<int, int>якщо ваші індекси мають особливе значення, окрім лише позиційного розміщення.

Безпосереднім прикладом, який спадає на думку, є зберігання стовпця id та int колонки в базі даних. Наприклад, якщо у вас є [person-id]стовпець і [personal-pin]стовпець, ви можете перенести їх у Dictionary<int, int>. Таким чином pinDict[person-id]ви отримуєте PIN-код, але індекс є значимим, а не лише позицією в List<int>.

Але дійсно, щоразу, коли у вас є два пов'язані списки цілих чисел, це може бути відповідною структурою даних.


Якщо мій ідентифікатор особи є з діапазону 0, ..., 999, і мені доведеться завантажувати особисті значення PIN-коду в пам'ять для всіх 1000 осіб, я зазвичай вибираю а List<int>, а не словник. Дивіться мою відповідь нижче.
Док Браун

3
так, але словник може бути рідким
jk.

@jk: саме це я намагався розробити у своїй відповіді.
Док Браун

7
Особистий PIN-код? Звуки щось надлишкові.
Джек

Гм, коли індекс має "особливе значення", в реальних світових сценаріях може бути ймовірним, що вони не утворюють суміжного діапазону [0, ..., n] (хоча це не є обов'язковим), тому ця відповідь є не просто неправильно, але неточно. Тим не менше, рішення IMHO не повинно базуватися на цій "особливій значущій справі", а лише на "чи ключі будують приблизно інтервал [0, ..., n]". Виходячи з кількості оновлених даних, я думаю, більшість читачів пропустили цю точку.
Док Браун

28

Подумайте Listяк масив і Dictionaryяк хеш-таблицю . Ви б використовували лише те, Dictionaryякщо вам потрібно було зіставити (або пов’язати) значущі ключі до значень, тоді як Listлише карта (або асоційовані) позиції (або індекси) до значень.

Наприклад, скажіть, що ви хотіли зберегти асоціацію між віком людини та їх зростом. Ви можете скористатися Dictionary<int, int>карткою, щоб зіставити вік (і int) людини на їх зріст (an int):

Dictionary<int, int> personHeightMap = new Dictionary<int, int>();

personHeightMap.Add(21, 185);
personHeightMap.Add(31, 174);

int height = personHeightMap.ContainsKey(21) ? personHeightMap[21] : -1;

Не дуже корисний приклад, але справа в тому, що ви не зможете зробити це так елегантно, Listтому що потрібно буде зберігати ці значення на позиційному рівні.


7
+1 для згадки про те, що Listугода з замовленням , де Dictionaryугода про асоціацію . Якщо вам потрібно отримувати ваші дані в певному порядку щоразу або їх порядок відносно один одного важливий, Listце шлях. Dictionariesмають тенденцію бути не упорядкованими і мати справу з відображенням співвідношень ключів -> цінностей.
KChaloux

2
Не в останню чергу, коли ви знаєте, що шукаєте, хеш-таблиця становить приблизно O (1) час, тоді як масив - O (logN) у кращому випадку (відсортовано та без дублікатів) та O (N) у найгірший випадок.
JensG

1
+1. Ніхто інший, здається, не звертався до того, що списки є семантично упорядкованими, а дикти - це семантично шукані, що , на мою думку, абсолютно принципово .
Бенджамін Ходжсон

15

Семантично, a Dictionary<int, T>і List<T>дуже схожі, обидва є контейнерами з випадковим доступом в .NET-рамках. Щоб використовувати список як заміну для словника, вам потрібно спеціальне значення у вашому типі T(як null), щоб представити порожні слоти у вашому списку. Якщо Tце не нульовий тип на зразок int, ви можете використовувати його int?замість цього, або якщо ви просто розраховуєте зберегти позитивні значення, ви також можете використати спеціальне значення, наприклад -1 для представлення порожніх слотів.

Який із них ви виберете, має залежати від діапазону ключових значень. Якщо ваші ключі знаходяться в цілому Dictionary<int, T>інтервалі, без багатьох проміжків між ними (наприклад, 80 значень поза [0, ... 100]), то а List<T>буде більш доцільним, оскільки доступ за індексом швидший, і в цьому випадку менше пам'яті та витрат часу в порівнянні зі словником.

Якщо ваші ключові значення - 100 intзначень з діапазону, як [0, ..., 1000000], тоді List<T>потрібна пам'ять, щоб вмістити 1000000 значень T, де вашому словнику просто знадобиться пам'ять на порядок близько 100 значень T, 100 значень int (плюс деякі накладні, насправді очікуйте приблизно в 2 рази більше пам’яті для зберігання цих 100 клавіш і значень). Тож в останньому випадку словник буде більш доречним.


6
це важлива відмінність imho, словник <int, int> може бути рідким
jk.

У цьому випадку чи не можемо ми використовувати Список <KeyValuePair <int, int >>? Який із них краще для лінійного обходу?
Діпак Мішра

@DeepakMishra: головна відмінність тут полягає в тому List<KeyValuePair<int,T>>, що немає операції пошуку O (1). По-друге, елементи в List<KeyValuePair<int,T>>можуть мати конкретне впорядкування, незалежне від їх ключових значень. Якщо вам потрібна остання , але не колишній, List<KeyValuePair<int,T>>чи List<Tuple<int,T>>може бути кращим вибором. Якщо вам потрібно і те, і інше OrderedDictionary.
Док Браун

@DocBrown Який з них буде кращим для лінійного переходу (тобто foreach) та операції вставки, не потрібно прямого пошуку?
Діпак Мішра

@DeepakMishra: у розробці програмного забезпечення не існує такого поняття, як "взагалі краще". Тут краще може означати швидше, краще читати, менше вводити код, простіше розширити для майбутніх вимог. Але загалом, перестаньте думати про це, застосуйте те, що вирішує вашу проблему під рукою правильно та найпростішим у ваших очах , перевірте, чи досить швидко вона відповідає вашим цілям , і вкладайте в неї лише більше думок, коли спостерігаєте недоліки.
Doc Brown

6

Як хто може вважати їх рівнозначними?

Словник є рідким і дозволяє випадкові вставки, але створює проблему в порядку замовлення, Список не є рідким, а вставлення поза порядком дороге, воно по суті забезпечує перехід порядку.

Було б дуже мало ситуацій, коли одна не була кардинально перевершує іншу.


2

Убік: Інші мови програмування називають цей тип структури даних як Map, а не як словник.

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

Наприклад, припустимо, у вас є список Клієнтів. Кожен Замовник містить реквізити, такі як ім’я та адресу та унікальний номер замовника. Припустимо, у вас також є список замовлень, які обробляються. Кожне замовлення міститиме детальну інформацію про те, що робиться, і потрібно буде вказати номер замовника особи, яка його замовила.

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


1

Словник використовує хешування для пошуку даних. Словник спочатку розраховував хеш-значення для ключа, і це хеш-значення призводить до цільового пакета даних. Після цього кожен елемент у відрі потрібно перевірити на рівність. Але насправді список буде швидшим, ніж словник під час пошуку першого пункту, оскільки нічого не потрібно шукати на першому кроці. Але на другому кроці в списку потрібно переглянути перший пункт, а потім другий. Тому пошук кожного кроку займає все більше і більше часу. Чим більший список, тим більше часу займає.

Більше про .... Словник проти списку з прикладом.


-1

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


-3

Це чудові відповіді, які, здається, покривають основи.

Ще один розгляд, який я запропоную, є те, що словники (в C #) є складнішими з точки зору кодування. Наявність списків і словників в одній і тій же кодовій базі ускладнює підтримку вашого коду тим, що обидва способи мають тонкі відмінності в тому, як робити основні операції, такі як пошук та об'єднання даних з об'єктом маршалінгу. Моя точка зору полягає в тому, що, якщо вам не потрібен словник з якоїсь виправданої причини, використовуйте список.


8
Я не погоджуюсь. Словник / карта є основоположною структурою даних, з якою повинен інтенсивно ознайомитися кожен програмний інженер. У будь-якому випадку: вам потрібна обгрунтована причина, щоб використовувати будь-яку структуру даних; включаючи Список.
Стівен Еверс
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.