Unterschied zwischen Lookup () und Dictionary (Of list ())

165

Ich versuche mich darum zu kümmern, welche Datenstrukturen am effizientesten sind und wann / wo welche verwendet werden sollen.

Nun könnte es sein, dass ich die Strukturen einfach nicht gut genug verstehe, aber wie unterscheidet sich eine ILookup(of key, ...)von einer Dictionary(of key, list(of ...))?

Auch wo würde ich ein verwenden wollen ILookupund wo wäre es effizienter in Bezug auf Programmgeschwindigkeit / Speicher / Datenzugriff usw.?

John Bustos
quelle
1
Man möchte vielleicht auch sehen, was der Sinn des Lookuptkey-Telements ist
nawfal

Antworten:

255

Zwei signifikante Unterschiede:

  • Lookupist unveränderlich. Yay :) (Zumindest glaube ich, dass die konkrete LookupKlasse unveränderlich ist und die ILookupSchnittstelle keine mutierenden Mitglieder bereitstellt. Es könnte natürlich auch andere veränderbare Implementierungen geben.)
  • Wenn Sie einen Schlüssel suchen, der in einer Suche nicht vorhanden ist, erhalten Sie anstelle von a eine leere Sequenz zurück KeyNotFoundException. (Daher gibt es keine TryGetValue, AFAICR.)

Ihre Effizienz ist wahrscheinlich gleichwertig - bei der Suche kann beispielsweise ein Blick Dictionary<TKey, GroupingImplementation<TValue>>hinter die Kulissen verwendet werden. Wählen Sie je nach Ihren Anforderungen zwischen ihnen. Persönlich finde ich, dass die Suche normalerweise besser passt als a Dictionary<TKey, List<TValue>>, hauptsächlich aufgrund der ersten beiden Punkte oben.

Beachten Sie, dass als Implementierungsdetail, dessen konkrete Implementierung IGrouping<,>für die Werte implementiert wird IList<TValue>, implementiert wird , was bedeutet, dass die Verwendung mit usw. effizient Count()ist ElementAt().

Jon Skeet
quelle
Wenn eine nicht vorhandene Schlüsselsuche eher zu einer leeren Sequenz als zu einer Ausnahme führt, kann sie im Allgemeinen nicht als allgemeine Sammlungssammlung verwendet werden. Es ist ein bisschen in Ordnung, wenn eine unveränderliche Sammlung ein Nebenprodukt von Linq-Abfragen ist.
Nawfal
@nawfal - genau dafür sind Lookups gedacht. Von msdn : "Sie können eine Instanz eines Lookup <TKey, TElement> erstellen, indem Sie ToLookup für ein Objekt aufrufen, das IEnumerable <T> implementiert."
Niall Connaughton
50

Interessant, dass niemand den tatsächlich größten Unterschied angegeben hat (direkt aus MSDN entnommen ):

Eine Suche ähnelt einem Wörterbuch. Der Unterschied besteht darin, dass ein Wörterbuch Schlüssel einzelnen Werten zuordnet, während ein Lookup Schlüssel Sammlungen von Werten zuordnet.

Mladen Mihajlovic
quelle
51
Überprüfen Sie die Frage: Es geht um den Unterschied zwischen einem Lookup <TKey, TValue> und einem Dictionary <TKey, List <TValue >>, sodass dieser Unterschied bereits explizit ist.
Martao
5
@Martao Einige Leute finden diese Frage beim Googeln, um den Unterschied zwischen Lookups und Wörterbüchern zu verstehen. Diese Antwort ist wirklich nützlich.
Jakubiszon
34

Sowohl a Dictionary<Key, List<Value>>als auch a können Lookup<Key, Value>logischerweise Daten enthalten, die auf ähnliche Weise organisiert sind, und beide haben dieselbe Effizienzreihenfolge. Der Hauptunterschied ist, dass a Lookupunveränderlich ist: Es gibt keine Add()Methoden und keinen öffentlichen Konstruktor (und wie Jon erwähnt hat, können Sie einen nicht vorhandenen Schlüssel ohne Ausnahme abfragen und den Schlüssel als Teil der Gruppierung haben).

Welche Sie verwenden, hängt wirklich davon ab, wie Sie sie verwenden möchten. Wenn Sie eine Zuordnung von Schlüsseln zu mehreren Werten pflegen, die ständig geändert wird, Dictionary<Key, List<Value>>ist a wahrscheinlich besser, da es veränderbar ist.

Wenn Sie jedoch eine Datenfolge haben und nur eine schreibgeschützte Ansicht der nach Schlüssel geordneten Daten wünschen, ist eine Suche sehr einfach zu erstellen und liefert einen schreibgeschützten Schnappschuss.

James Michael Hare
quelle
11

Der Hauptunterschied zwischen an ILookup<K,V>und a Dictionary<K, List<V>>besteht darin, dass ein Wörterbuch veränderlich ist. Sie können Schlüssel hinzufügen oder entfernen sowie Elemente zur nachgeschlagenen Liste hinzufügen oder daraus entfernen. Ein ILookupist unveränderlich und kann nach seiner Erstellung nicht mehr geändert werden.

Die zugrunde liegende Implementierung beider Mechanismen ist entweder gleich oder ähnlich, sodass ihre Suchgeschwindigkeit und ihr Speicherbedarf ungefähr gleich sind.

Servieren
quelle
1
@ JohnBustos In Bezug auf die Leistung, nein. Es ist rein logisch. Sie können Verweise auf die Struktur weitergeben, ohne sich Sorgen machen zu müssen, dass jemand anderes sie unter Ihnen ändert. Sie können davon ausgehen, dass es unveränderlich ist, dass Sie es nicht könnten, wenn es veränderlich wäre.
Servy
Danke, Servy, das ist ein sehr guter Punkt, wenn Sie so viele Variablen ByRef oft weitergeben - zumindest diese, von der Sie sicher sind, dass sie nicht geändert werden kann. Vielen Dank!
John Bustos
2
@JohnBustos Beachten Sie, dass die Standardmethode zum Übergeben eines Methodenparameters nach Wert ist. Sie müssen byref explizit hinzufügen. Dies sollte recht selten erfolgen. Diese Datenstrukturen sind Klassen, wodurch sie zu Referenztypen werden. Die Übergabe des Werts ist also der Wert der Referenz. Daher kann die Übergabe an eine andere Methode sichtbare Änderungen für den Aufrufer verursachen.
Servy
Danke, Servy, das eröffnet mir eine ganz neue Dose Würmer in Bezug auf das, was ich getan habe :), aber ich verstehe, was du sagst. Vielen Dank!!
John Bustos
Wissen Sie unter der Decke, ob Lookup Hashbuckets für den Schlüssel verwendet?
Paparazzo
10

Ein weiterer Unterschied, der noch nicht erwähnt wurde, ist, dass Lookup () Nullschlüssel unterstützt :

Die Lookup-Klasse implementiert die ILookup-Schnittstelle. Die Suche ist einem Wörterbuch sehr ähnlich, außer dass mehrere Werte demselben Schlüssel zugeordnet werden dürfen und Nullschlüssel unterstützt werden.

Noble_Bright_Life
quelle
4

Wenn eine Ausnahme keine Option ist, wählen Sie Nachschlagen

Wenn Sie versuchen, eine so effiziente Struktur wie eine zu erhalten, Dictionaryaber nicht sicher sind, dass die Eingabe keinen doppelten Schlüssel enthält, Lookupist dies sicherer.

Wie in einer anderen Antwort erwähnt, unterstützt es auch Nullschlüssel und gibt immer ein gültiges Ergebnis zurück, wenn es mit beliebigen Daten abgefragt wird, sodass es für unbekannte Eingaben widerstandsfähiger erscheint (weniger anfällig als Dictionary, Ausnahmen auszulösen).

Und es ist besonders wahr, wenn Sie es mit der System.Linq.Enumerable.ToDictionaryFunktion vergleichen:

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

Die Alternative wäre, Ihren eigenen doppelten Schlüsselverwaltungscode in eine foreachSchleife zu schreiben .

Leistungsüberlegungen, Wörterbuch: ein klarer Gewinner

Wenn Sie keine Liste benötigen und eine große Anzahl von Elementen verwalten Dictionarymöchten (oder sogar Ihre eigene maßgeschneiderte Struktur), ist dies effizienter:

        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);
        // ...

Da Lookupfür jeden Schlüssel eine Liste mit Elementen geführt werden muss, ist diese langsamer als das Wörterbuch (etwa dreimal langsamer für eine große Anzahl von Elementen).

Suchgeschwindigkeit: Erstellung: 00: 00: 01.5760444

Wörterbuchgeschwindigkeit: Erstellung: 00: 00: 00.4418833

Fab
quelle