Різниця між пошуком () та словником (списку ())


165

Я намагаюся обернути голову навколо того, які структури даних є найбільш ефективними та коли / де використовувати які.

Можливо, я просто не розумію структури досить добре, але чим вона ILookup(of key, ...)відрізняється від Dictionary(of key, list(of ...))?

Також де я хотів би використовувати ILookupі де це було б більш ефективно в плані швидкості програми / доступу до пам'яті / даних тощо?


1
ви також можете побачити, що таке-є-точка-lookuptkey-telement
nawfal

Відповіді:


255

Дві суттєві відмінності:

  • Lookupнезмінна. Так :) (Принаймні, я вважаю, що конкретний Lookupклас незмінний, а ILookupінтерфейс не забезпечує жодних мутуючих членів. Звичайно, можуть бути й інші зміни, що змінюються).
  • Коли ви шукаєте ключ, який відсутній у пошуку, ви отримуєте назад порожню послідовність замість KeyNotFoundException. (Значить, немає TryGetValue, AFAICR.)

Вони, швидше за все, будуть еквівалентними по ефективності - наприклад, пошук може використовуватись Dictionary<TKey, GroupingImplementation<TValue>>поза кадром, наприклад. Вибирайте між ними, виходячи зі своїх вимог. Особисто я вважаю, що пошук зазвичай краще підходить, ніж a Dictionary<TKey, List<TValue>>, в основному завдяки першим двом пунктам вище.

Зверніть увагу , що в якості деталей реалізації, конкретна реалізація IGrouping<,>якого використовується для значень знарядь IList<TValue>, що означає , що він ефективний для використання з Count(), і ElementAt()так далі


Якщо неіснуючий пошук ключа призводить до порожньої послідовності, а не до винятку, він дуже не може бути використаний як imo колекції загального призначення. Це ніби нормально у випадку незмінної колекції, яка є побічним продуктом linq-запитів.
nawfal

@nawfal - саме для цього і шукають Lookups. З msdn : "Ви можете створити екземпляр пошуку <TKey, TElement>, викликавши ToLookup на об'єкті, який реалізує IEnumerable <T>."
Niall Connaughton

50

Цікаво, що ніхто не констатував фактично найбільшу різницю (взято безпосередньо з MSDN ):

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


51
Перевірте питання: мова йде про різницю між Lookup <TKey, TValue> та словником <TKey, List <TValue>>, так що ця різниця вже є явною.
Мартао

5
@Martao деякі люди знаходять це питання, коли Google розуміють різницю між пошуковими запитами та словниками. Ця відповідь справді корисна.
jakubiszon

34

І a, Dictionary<Key, List<Value>>і Lookup<Key, Value>логічно можуть зберігати дані, організовані аналогічно, і обидва мають однаковий порядок ефективності. Основна відмінність a Lookupє непорушною: вона не має Add()методів і жодного публічного конструктора (і, як згадував Джон, ви можете запитувати неіснуючий ключ без винятку і мати ключ у складі групування).

Щодо того, яким ти користуєшся, то насправді залежить від того, як ти хочеш ними користуватися. Якщо ви підтримуєте карту, що має ключ до кількох значень, яка постійно змінюється, то a Dictionary<Key, List<Value>>, мабуть, краще, оскільки воно є змінним.

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


11

Основна різниця між a ILookup<K,V>і a Dictionary<K, List<V>>полягає в тому, що словник може змінюватися; ви можете додавати або видаляти ключі, а також додавати або видаляти елементи зі списку, який шукається. ILookupЄ непорушним і не можуть бути змінені після створення.

Основа реалізації обох механізмів буде або однаковою, або подібною, тому швидкість їх пошуку та слід пам’яті будуть приблизно однаковими.


1
@JohnBustos З точки зору продуктивності, немає. Це цілком логічно. Ви можете передавати посилання на структуру навколо, не турбуючись про те, щоб хтось змінив її з-під вас. Ви можете зробити припущення про те, що це незмінне, що ви не могли б змінити його.
Сервіс

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

2
@JohnBustos Майте на увазі, що метод за замовчуванням передачі параметра методу є за значенням, вам потрібно явно додати byref, і це те, що потрібно робити досить рідко. Ці структури даних є класами, що робить їх еталонними типами, тому передача значення - це значення посилання, саме тому передача його іншому методу може викликати видимі зміни у абонента.
Сервіс

Дякую, Серві, що відкриває для мене цілу нову глистину глину з точки зору того, що я робив :), але я розумію, що ти говориш. Дякую!!
Джон Бустос

Під обкладинками ви знаєте, чи Lookup використовує хешбуки для ключа?
папараццо

10

Ще одна відмінність, яка ще не згадується, полягає в тому, що Lookup () підтримує нульові ключі :

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


4

Якщо виняток не є варіантом, перейдіть на пошук

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

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

І це особливо вірно, якщо порівнювати його з System.Linq.Enumerable.ToDictionaryфункцією:

// won't throw
new[] { 1, 1 }.ToLookup(x => x); 

// System.ArgumentException: An item with the same key has already been added.
new[] { 1, 1 }.ToDictionary(x => x);

Альтернативою було б написати власний дублікат коду управління ключами всередині foreachциклу.

Міркування щодо ефективності, словник: явний переможець

Якщо вам не потрібен список, і ви збираєтеся керувати величезною кількістю елементів Dictionary(або навіть власну індивідуальну структуру), було б більш ефективно:

        Stopwatch stopwatch = new Stopwatch();
        var list = new List<string>();
        for (int i = 0; i < 5000000; ++i)
        {
            list.Add(i.ToString());
        }
        stopwatch.Start();
        var lookup = list.ToLookup(x => x);
        stopwatch.Stop();
        Console.WriteLine("Creation: " + stopwatch.Elapsed);

        // ... Same but for ToDictionary
        var lookup = list.ToDictionary(x => x);
        // ...

Оскільки Lookupдоводиться вести список елементів для кожної клавіші, він повільніше, ніж словник (приблизно в 3 рази повільніше для величезної кількості елементів)

Швидкість пошуку: Створення: 00: 00: 01.5760444

Швидкість словника: Створення: 00: 00: 00.4418833

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