Який сенс пошуку <TKey, TElement>?


155

MSDN пояснює пошук таким чином:

А Lookup<TKey, TElement> нагадує а Dictionary<TKey, TValue>. Різниця полягає в тому, що словник <TKey, TValue> позначає ключі до одиничних значень, тоді як Lookup <TKey, TElement> відображає ключі до колекцій значень.

Я не вважаю це пояснення особливо корисним. Для чого використовується пошук?

Відповіді:


215

Це хрест між IGroupingсловником та словником. Він дозволяє групувати елементи разом за ключем, але потім ефективно отримувати доступ до них за допомогою цього ключа (а не просто повторювати їх над усіма, ось щоGroupBy дозволяє робити).

Наприклад, ви можете скористатися типом .NET і побудувати пошук по простору імен ..., а потім легко легко дістатися до всіх типів у певній області імен:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;

public class Test
{
    static void Main()
    {
        // Just types covering some different assemblies
        Type[] sampleTypes = new[] { typeof(List<>), typeof(string), 
                                     typeof(Enumerable), typeof(XmlReader) };

        // All the types in those assemblies
        IEnumerable<Type> allTypes = sampleTypes.Select(t => t.Assembly)
                                               .SelectMany(a => a.GetTypes());

        // Grouped by namespace, but indexable
        ILookup<string, Type> lookup = allTypes.ToLookup(t => t.Namespace);

        foreach (Type type in lookup["System"])
        {
            Console.WriteLine("{0}: {1}", 
                              type.FullName, type.Assembly.GetName().Name);
        }
    }
}

(Я зазвичай використовую varдля більшості цих декларацій у звичайному коді.)


59
Я думаю, щоб покращити цю відповідь, ви могли б замінити деякі варі. Для цілей навчання я думаю, що легше наслідувати, коли типи виражені чітко. Тільки мої 2 копійки :)
Олексій Бараноський

3
Якщо він має найкращі з обох світів, то навіщо турбуватися зі словником?
Кайл Баран

15
@KyleBaran: Тому що для справжніх колекцій пар ключів / значень було б безглуздо, де на ключ є лише одне значення.
Джон Скіт

12
@KyleBaran Lookup<,>- це просто незмінна колекція (без Addметоду, наприклад), яка має обмежене використання. Крім того, це не колекція загального призначення в тому сенсі, що якщо ви здійснюєте пошук за неіснуючим ключем, ви отримуєте порожню послідовність, а не виняток, що має сенс лише у спеціальних контекстах, наприклад, з linq. Це добре поєднується з тим, що MS не надала громадський конструктор для класу.
nawfal

Читання замовлення відповідей ПТМ -> bobbymcr -> jonskeet
ЗСШ

58

Один із способів задуматися над цим: Lookup<TKey, TElement>подібний Dictionary<TKey, Collection<TElement>>. В основному список нульових або більше елементів можна повернути за допомогою одного і того ж ключа.

namespace LookupSample
{
    using System;
    using System.Collections.Generic;
    using System.Linq;

    class Program
    {
        static void Main(string[] args)
        {
            List<string> names = new List<string>();
            names.Add("Smith");
            names.Add("Stevenson");
            names.Add("Jones");

            ILookup<char, string> namesByInitial = names.ToLookup((n) => n[0]);

            // count the names
            Console.WriteLine("J's: {0}", namesByInitial['J'].Count()); // 1
            Console.WriteLine("S's: {0}", namesByInitial['S'].Count()); // 2
            Console.WriteLine("Z's: {0}", namesByInitial['Z'].Count()); // 0, does not throw
        }
    }
}

2
Чи може бути результат нульових елементів у пошуку? Як би ти це отримав? (Пошук є незмінним для всіх, наскільки я можу сказати, і я не думаю, що ToLookup ефективно вигадує ключі.)
Джон Скіт,

8
Технічно, так, оскільки Lookup повертає порожню колекцію для неіснуючого ключа (я відредагував свою публікацію, щоб додати зразок коду, який це показує).
bobbymcr

Читання замовлення відповідей ПТМ -> bobbymcr -> jonskeet
ЗСШ

Дуже чиста і корисна відповідь, я б хотів, щоб вона була обрана.
хвилини

25

Одним із можливих застосувань Lookupможе бути зворотний зв'язок Dictionary.

Припустимо, у вас телефонна книга реалізована як Dictionaryбукет із (унікальними) іменами як ключі, кожне ім’я пов'язане з номером телефону. Але двоє людей з різними іменами можуть мати один і той же номер телефону. Це не проблема дляDictionary , що не важливо, щоб дві клавіші відповідали одному і тому ж значенню.

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

dictionary["555-6593"] = "Dr. Emmett Brown";
dictionary["555-6593"] = "Marty McFly";

означає, що другий запис перезаписує перший - Doc більше не в списку.

Намагання записати ті самі дані трохи по-іншому:

dictionary.Add("555-6593", "Dr. Emmett Brown");
dictionary.Add("555-6593", "Marty McFly");

викине виняток на другий рядок, оскільки ви не можете Addввести ключ, який вже є Dictionary.

[Звичайно, ви можете використовувати деякі інші структури даних одного , щоб зробити пошуки в обох напрямках, і т.д. Цей приклад означає , що ви повинні регенерувати Lookupз Dictionaryкожної пори останньої зміни. Але для деяких даних це може бути правильним рішенням.]


Відповідь життєво важлива для розуміння концепції. +1. Читання замовлення відповідей ПТМ -> bobbymcr -> jonskeet
ЗСШ

15

Я не успішно використовував його раніше, але ось мій шлях:

A Lookup<TKey, TElement>поводився б майже як (реляційний) індекс бази даних на столі без унікального обмеження. Використовуйте його в тих же місцях, де ви б використовували інші.


5

Я думаю, ви могли б це аргументувати так: уявіть, ви створюєте структуру даних для вмісту вмісту телефонної книги. Ви хочете ввести ключ LastName, а потім firstName. Використовувати тут словник було б небезпечно, оскільки багато людей можуть мати те саме ім’я. Таким чином, Словник завжди, максимум, відображатиметься до одного значення.

Пошук буде відображати на кілька потенційно значень.

Пошук ["Smith"] ["John"] буде колекцією розміром один мільярд.


Ваша відповідь надихнула мого подальшого запитання "Як ToLookup () з кількома індексами?" . Як я можу відтворити таке, за допомогою кількох індексів, пошук? Чи можете ви відповісти на це, можливо, використовуючи будь-який інший зразок або посилання, де це можливо використовувати Lookup["Smith"]["John"] ?
Повний захист
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.