Какова точка поиска <TKey, TElement>?

MSDN объясняет поиск следующим образом:

A Lookup<TKey, TElement>напоминает Dictionary<TKey, TValue>. Разница в том, что Словарь < TKey, TValue > сопоставляет ключи с одиночными значениями, тогда как Lookup < TKey, TElement > отображает ключи в коллекции значений.

Я не считаю это объяснение особенно полезным. Для чего используется Lookup?

Ответ 1

Это крест между 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 для большинства этих объявлений в обычном коде.)

Ответ 2

Один из способов подумать об этом: 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());
            Console.WriteLine("S's: {0}", namesByInitial['S'].Count());
            Console.WriteLine("Z's: {0}", namesByInitial['Z'].Count());
        }
    }
}

Ответ 3

Одно использование Lookup может заключаться в обратном преобразовании Dictionary.

Предположим, что у вас есть телефонная книга, реализованная как Dictionary с пучком (уникальными) именами в качестве ключей, каждое имя связано с номером телефона. Но два человека с разными именами могут иметь один и тот же номер телефона. Это не проблема для Dictionary, которая не заботится о том, чтобы две клавиши соответствовали одному значению.

Теперь вам нужен способ поиска, кому принадлежит данный номер телефона. Вы создаете Lookup, добавляя все KeyValuePairs из вашего Dictionary, но назад, со значением в качестве ключа и ключа в качестве значения. Теперь вы можете запросить номер телефона и получить список имен всех людей, у которых есть номер телефона. Построение a 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 каждый раз, когда последний изменяется. Но для некоторых данных это может быть правильным решением.]

Ответ 4

Я не использовал его раньше, но вот мой ход:

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

Ответ 5

Я думаю, вы могли бы так утверждать: представьте, что вы создаете структуру данных для хранения содержимого телефонной книги. Вы хотите использовать ключ lastName, а затем firstName. Использование словаря здесь было бы опасно, потому что многие люди могут иметь одно и то же имя. Таким образом, словарь всегда будет, в лучшем случае, сопоставляться с одним значением.

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

Поиск [ "Смит" ] [ "Джон" ] будет представлять собой коллекцию размером один миллиард.