Jaki jest cel Lookup <TKey, TElement>?

155

MSDN wyjaśnia Lookup w następujący sposób:

A Lookup<TKey, TElement> przypomina a Dictionary<TKey, TValue>. Różnica polega na tym, że Dictionary <TKey, TValue> mapuje klucze na pojedyncze wartości, podczas gdy Lookup <TKey, TElement> mapuje klucze na kolekcje wartości.

Nie uważam tego wyjaśnienia za szczególnie pomocne. Do czego służy Lookup?

dan-gph
źródło

Odpowiedzi:

215

To skrzyżowanie IGroupingsłownika i słownika. Pozwala grupować elementy razem według klucza, ale następnie uzyskiwać do nich dostęp za pomocą tego klucza w efektywny sposób (zamiast po prostu iterować je wszystkie, co GroupBypozwala na to).

Na przykład, możesz wziąć ładunek typów .NET i utworzyć wyszukiwanie według przestrzeni nazw ... a następnie bardzo łatwo uzyskać dostęp do wszystkich typów w określonej przestrzeni nazw:

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

(Zwykle używałbym vardla większości tych deklaracji, w normalnym kodzie.)

Jon Skeet
źródło
59
Myślę, że aby ulepszyć tę odpowiedź, możesz wymienić niektóre z vars. Myślę, że w celach edukacyjnych łatwiej jest naśladować, gdy typy są jasno wyrażone. Tylko moje 2 centy :)
Alex Baranosky,
3
Jeśli ma to, co najlepsze z obu światów, to po co zawracać sobie głowę słownikiem?
Kyle Baran,
15
@KyleBaran: Ponieważ byłoby to bezcelowe w przypadku oryginalnych kolekcji par klucz / wartość, w których jest tylko jedna wartość na klucz.
Jon Skeet,
12
@KyleBaran Lookup<,>to po prostu niezmienna kolekcja (bez Addmetody np.), Która ma ograniczone zastosowanie. Co więcej, nie jest to zbiór ogólnego przeznaczenia w tym sensie, że jeśli wyszukasz nieistniejący klucz, otrzymasz pustą sekwencję zamiast wyjątku, co ma znaczenie tylko w specjalnych kontekstach, na przykład w linq. Zgadza się to z faktem, że firma MS nie udostępniła publicznego konstruktora dla tej klasy.
nawfal
Kolejność czytania odpowiedzi to jwg -> bobbymcr -> jonskeet
snr
58

Można o tym pomyśleć: Lookup<TKey, TElement>jest podobny do Dictionary<TKey, Collection<TElement>>. Zasadniczo lista zawierająca zero lub więcej elementów może zostać zwrócona za pomocą tego samego klucza.

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
        }
    }
}
bobbymcr
źródło
2
Czy wynik wyszukiwania może zawierać zero elementów? Jak byś to zdobył? (Lookup jest publicznie niezmienny, o ile wiem, i nie sądzę, aby ToLookup skutecznie wymyślił klucze.)
Jon Skeet
8
Technicznie tak, ponieważ Lookup zwraca pustą kolekcję dla nieistniejącego klucza (edytowałem mój post, aby dodać przykładowy kod, który to pokazuje).
bobbymcr
Kolejność czytania odpowiedzi to jwg -> bobbymcr -> jonskeet
snr
Bardzo czysta i pomocna odpowiedź, chciałbym, żeby została wybrana.
min
25

Jednym z zastosowań Lookupmoże być odwrócenie pliku Dictionary.

Załóżmy, że masz książkę telefoniczną zaimplementowaną jako zestaw Dictionary(unikalnych) nazw jako kluczy, z których każda jest powiązana z numerem telefonu. Ale dwie osoby o różnych nazwach mogą mieć ten sam numer telefonu. Nie stanowi to problemu dla a Dictionary, który nie przejmuje się tym, że dwa klucze odpowiadają tej samej wartości.

Teraz potrzebujesz sposobu na sprawdzenie, do kogo należy dany numer telefonu. Budujesz Lookup, dodając wszystkie KeyValuePairsz twojego Dictionary, ale wstecz, z wartością jako kluczem i kluczem jako wartością. Możesz teraz zapytać o numer telefonu i uzyskać listę nazwisk wszystkich osób, których to numer telefonu. Budowanie Dictionaryz tymi samymi danymi spadnie dane (lub nie, w zależności od tego, jak to zrobił), ponieważ robi

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

oznacza, że ​​drugi wpis zastępuje pierwszy - dokumentu nie ma już na liście.

Próbuję zapisać te same dane w nieco inny sposób:

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

zgłosiłby wyjątek w drugiej linii, ponieważ nie można Addużyć klucza, który jest już w Dictionary.

[Oczywiście, możesz chcieć użyć jakiejś innej pojedynczej struktury danych do wyszukiwania w obu kierunkach, itd. Ten przykład oznacza, że ​​musisz ponownie wygenerować dane Lookupz Dictionarykażdej zmiany tej ostatniej. Ale w przypadku niektórych danych może to być właściwe rozwiązanie.]

jwg
źródło
Odpowiedź jest niezbędna do zrozumienia koncepcji. +1. Kolejność czytania odpowiedzi to jwg -> bobbymcr -> jonskeet
snr
15

Nie korzystałem z niego wcześniej, ale oto moja kolej:

A Lookup<TKey, TElement>zachowywałby się prawie jak (relacyjny) indeks bazy danych w tabeli bez ograniczenia unikalności. Użyj go w tych samych miejscach, w których używałbyś drugiego.

Daren Thomas
źródło
5

Myślę, że można to argumentować w ten sposób: wyobraź sobie, że tworzysz strukturę danych do przechowywania zawartości książki telefonicznej. Chcesz wprowadzić klucz przez lastName, a następnie przez firstName. Używanie tutaj słownika byłoby niebezpieczne, ponieważ wiele osób może mieć to samo imię. Zatem słownik zawsze będzie mapował co najwyżej pojedynczą wartość.

Lookup mapuje potencjalnie kilka wartości.

Lookup [„Smith”] [„John”] będzie zbiorem o wielkości jednego miliarda.

David Andres
źródło
Twoja odpowiedź zainspirowała moje kolejne pytanie „How ToLookup () with multiple indexes?” . Jak mogę odtworzyć takie, z wieloma indeksami, wyszukiwanie? Czy mógłbyś odpowiedzieć na to ewentualnie używając jakiejkolwiek innej próbki lub odniesienia, jeśli jest to możliwe Lookup["Smith"]["John"] ?
Pełna odporność