Was ist der Sinn von Lookup <TKey, TElement>?

155

Der MSDN erklärt Lookup folgendermaßen:

A Lookup<TKey, TElement> ähnelt a Dictionary<TKey, TValue>. Der Unterschied besteht darin, dass ein Wörterbuch <TKey, TValue> Schlüssel einzelnen Werten zuordnet, während ein Lookup <TKey, TElement> Schlüssel Sammlungen von Werten zuordnet .

Ich finde diese Erklärung nicht besonders hilfreich. Wofür wird Lookup verwendet?

dan-gph
quelle

Antworten:

215

Es ist eine Kreuzung zwischen einem IGroupingund einem Wörterbuch. Sie können Elemente nach einem Schlüssel gruppieren und dann über diesen Schlüssel auf effiziente Weise darauf zugreifen (anstatt nur über alle zu iterieren, was GroupBySie tun können).

Sie könnten beispielsweise eine Menge .NET-Typen laden und eine Suche nach Namespace erstellen ... und dann ganz einfach zu allen Typen in einem bestimmten Namespace gelangen:

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

(Normalerweise würde ich varfür die meisten dieser Deklarationen normalen Code verwenden.)

Jon Skeet
quelle
59
Ich denke, um diese Antwort besser zu machen, könnten Sie einige der Vars ersetzen. Für Lernzwecke denke ich, dass es einfacher ist zu folgen, wenn die Typen klar ausgedrückt werden. Nur meine 2 Cent :)
Alex Baranosky
3
Wenn es das Beste aus beiden Welten hat, warum sollte man sich dann mit einem Wörterbuch beschäftigen?
Kyle Baran
15
@KyleBaran: Weil es für echte Schlüssel / Wert-Paar-Sammlungen sinnlos wäre, wenn es nur einen einzigen Wert pro Schlüssel gibt.
Jon Skeet
12
@KyleBaran Lookup<,>ist einfach eine unveränderliche Sammlung (ohne AddMethode für z. B.), die nur begrenzt verwendet werden kann. Darüber hinaus handelt es sich nicht um eine Allzweck-Sammlung in dem Sinne, dass Sie beim Nachschlagen eines nicht vorhandenen Schlüssels eher eine leere Sequenz als eine Ausnahme erhalten, was nur in speziellen Kontexten von Bedeutung ist, z. B. mit linq. Dies passt gut zu der Tatsache, dass MS keinen öffentlichen Konstruktor für die Klasse bereitgestellt hat.
Nawfal
Die Reihenfolge der Leseantworten lautet jwg -> bobbymcr -> jonskeet
snr
58

Eine Möglichkeit, darüber nachzudenken, ist folgende: Lookup<TKey, TElement>ähnelt Dictionary<TKey, Collection<TElement>>. Grundsätzlich kann eine Liste mit null oder mehr Elementen über denselben Schlüssel zurückgegeben werden.

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
quelle
2
Kann ein Suchergebnis keine Elemente enthalten? Wie würden Sie das bekommen? (Lookup ist öffentlich unveränderlich, soweit ich das beurteilen kann, und ich glaube nicht, dass ToLookup effektiv Schlüssel erfinden würde.)
Jon Skeet
8
Technisch gesehen ja, da eine Suche eine leere Sammlung für einen nicht vorhandenen Schlüssel zurückgibt (ich habe meinen Beitrag bearbeitet, um ein Codebeispiel hinzuzufügen, das dies zeigt).
Bobbymcr
Die Reihenfolge der Leseantworten lautet jwg -> bobbymcr -> jonskeet
snr
Eine sehr saubere und hilfreiche Antwort, ich wünschte, sie wäre ausgewählt worden.
Minuten
25

Eine Verwendung von Lookupkönnte sein, a umzukehren Dictionary.

Angenommen, Sie haben ein Telefonbuch implementiert, das eine DictionaryReihe von (eindeutigen) Namen als Schlüssel enthält, wobei jeder Name einer Telefonnummer zugeordnet ist. Zwei Personen mit unterschiedlichen Namen haben möglicherweise dieselbe Telefonnummer. Dies ist kein Problem für a Dictionary, das sich nicht darum kümmert, dass zwei Schlüssel demselben Wert entsprechen.

Jetzt möchten Sie nachschlagen, wem eine bestimmte Telefonnummer gehört. Sie erstellen ein Lookup, indem Sie alles KeyValuePairsvon Ihrem Dictionary, aber rückwärts, mit dem Wert als Schlüssel und dem Schlüssel als Wert hinzufügen . Sie können jetzt eine Telefonnummer abfragen und eine Liste mit Namen aller Personen abrufen, deren Telefonnummer dies ist. Das Erstellen eines Dictionarymit denselben Daten würde Daten löschen (oder fehlschlagen, je nachdem, wie Sie es getan haben)

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

bedeutet, dass der zweite Eintrag den ersten überschreibt - das Dokument wird nicht mehr aufgelistet.

Der Versuch, dieselben Daten auf etwas andere Weise zu schreiben:

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

würde eine Ausnahme in die zweite Zeile werfen, da Sie keinen AddSchlüssel finden können, der sich bereits in der befindet Dictionary.

[Natürlich möchten Sie vielleicht eine andere einzelne Datenstruktur verwenden Lookups in beide Richtungen zu tun, usw. In diesem Beispiel bedeutet , dass Sie die regenerieren haben Lookupaus dem Dictionarydie letzteren ändert sich jedes Mal. Aber für einige Daten könnte es die richtige Lösung sein.]

jwg
quelle
Die Antwort ist wichtig, um das Konzept zu verstehen. +1. Die Reihenfolge der Leseantworten lautet jwg -> bobbymcr -> jonskeet
snr
15

Ich habe es noch nicht erfolgreich verwendet, aber hier ist mein Ziel:

A Lookup<TKey, TElement>würde sich ziemlich ähnlich wie ein (relationaler) Datenbankindex für eine Tabelle ohne eine eindeutige Einschränkung verhalten. Verwenden Sie es an den gleichen Stellen, an denen Sie es auch verwenden würden.

Daren Thomas
quelle
5

Ich denke, Sie könnten es so argumentieren: Stellen Sie sich vor, Sie erstellen eine Datenstruktur für den Inhalt eines Telefonbuchs. Sie möchten nach Nachname und dann nach Vorname eingeben. Die Verwendung eines Wörterbuchs wäre hier gefährlich, da viele Personen denselben Namen haben können. Ein Wörterbuch wird also immer höchstens einem einzelnen Wert zugeordnet.

Eine Suche wird möglicherweise mehreren Werten zugeordnet.

Lookup ["Smith"] ["John"] wird eine Sammlung mit einer Größe von einer Milliarde sein.

David Andres
quelle
Ihre Antwort inspirierte meine Folgefrage "How ToLookup () mit mehreren Indizes?" . Wie kann ich eine solche Suche mit mehreren Indizes reproduzieren? Könnten Sie es möglicherweise mit einem anderen Beispiel oder einer anderen Referenz beantworten, wenn es möglich ist, es zu verwenden Lookup["Smith"]["John"] ?
Fulproof