Warum unterscheiden sich ToLookup und GroupBy?

110

.ToLookup<TSource, TKey>gibt ein zurück ILookup<TKey, TSource>. ILookup<TKey, TSource>implementiert auch Schnittstelle IEnumerable<IGrouping<TKey, TSource>>.

.GroupBy<TSource, TKey>gibt ein zurück IEnumerable<IGrouping<Tkey, TSource>>.

ILookup verfügt über die praktische Indexer-Eigenschaft, sodass es wie ein Wörterbuch (oder ein Lookup) verwendet werden kann, GroupBy jedoch nicht. GroupBy ohne Indexer ist ein Problem. Die einzige Möglichkeit, auf das Rückgabeobjekt zu verweisen, besteht darin, es zu durchlaufen (oder eine andere LINQ-Erweiterungsmethode zu verwenden). Mit anderen Worten, in jedem Fall, in dem GroupBy funktioniert, funktioniert ToLookup auch.

All dies lässt mich die Frage offen, warum ich mich jemals mit GroupBy beschäftigen sollte. Warum sollte es existieren?

Shlomo
quelle
7
GroupByIst IQuerable, ILookupist nicht
Magnus
5
GroupBy zählt die Liste nicht auf ToLookup zählt sie auf die gleiche Weise auf ToList / ToArray
Aducci
3
Ich habe dies für die Wiedereröffnung nominiert, da es sich bei der Frage, bei der es sich angeblich um ein Duplikat handelt, eher um IGrouping als um GroupBy und ILookup anstatt um ToLookup handelt . Die Unterschiede zwischen diesen unterscheiden sich von den Unterschieden zwischen diesen. Dies sollte sich aus den Unterschieden in den Antworten zwischen den Fragen ergeben.
Sam
1
Beide erstellen ein Lookup, aber es wird GroupByerstellt, wenn das Ergebnis aufgelistet ist. referencesource.microsoft.com/#System.Core/System/Linq/…
Slai

Antworten:

175

Warum sollte ich mich jemals mit GroupBy beschäftigen? Warum sollte es existieren?

Was passiert, wenn Sie ToLookup für ein Objekt aufrufen, das eine entfernte Datenbanktabelle mit einer Milliarde Zeilen darstellt?

Die Milliarden Zeilen werden über die Leitung gesendet, und Sie erstellen die Nachschlagetabelle lokal.

Was passiert, wenn Sie GroupBy für ein solches Objekt aufrufen?

Ein Abfrageobjekt wird erstellt. Ende der Geschichte.

Wenn dieses Abfrageobjekt aufgelistet ist, wird die Analyse der Tabelle auf dem Datenbankserver durchgeführt und die gruppierten Ergebnisse werden bei Bedarf nacheinander zurückgesendet .

Logischerweise sind sie dasselbe, aber die Auswirkungen auf die Leistung sind völlig unterschiedlich. Wenn ich ToLookup aufrufe, möchte ich einen Cache der gesamten Sache, der gerade nach Gruppen organisiert ist . Das Aufrufen von GroupBy bedeutet "Ich baue ein Objekt, um die Frage darzustellen, wie diese Dinge aussehen würden, wenn ich sie nach Gruppen organisieren würde."

Eric Lippert
quelle
6
Das Poster zielt nicht speziell auf eine IQueryable<T>Darstellung ab. Ihre Antwort deckt diese Situation ab, aber wenn es einfach nur alt ist IEnumerable<T>(LINQ-to-Objects), kann es so aussehen, als gäbe es keinen Grund, einen über den anderen zu verwenden. Ich glaube, @Shlomo versucht, dies zu erreichen. Nicht der IQueryable<T>Fall, sondern der Fall LINQ-to-Objects.
CasperOne
21
@casperOne: Ich denke, Sie haben meinen Standpunkt nicht verstanden. Auch in der LINQ-to-Objekten Fall ruft GroupBy noch nicht die Sammlung iterieren. (Wie Aducci in der Antwort, die Sie gelöscht haben, betont hat.) Das ist ein grundlegender Unterschied.
Eric Lippert
12
@EricLippert: Aber ist das nur ein Nebeneffekt der Implementierung oder ist garantiert, dass die Aufzählung beim Aufrufen von ToLookup wiederholt wird, unabhängig davon, welche Änderungen an der Implementierung vorgenommen werden?
9
@ Will: Sie machen einen ausgezeichneten Punkt; Die Dokumentation garantiert nicht, dass ToLookup "eifrig" ist. Es sollte das wahrscheinlich beachten.
Eric Lippert
10
Eagerness erklärt es. Die Sprache von 'ToMetaType' impliziert meiner Meinung nach Eifer; obwohl es offensichtlich der Umsetzung überlassen bleibt. Die anderen Aufgaben sind alle eifrig (ToList, ToArray, ToDictionary). Danke Leute.
Shlomo
97

In einfachen Worten der LINQ-Welt:

  • ToLookup() - sofortige Ausführung
  • GroupBy() - Aufgeschobene Ausführung
sll
quelle
17

Die beiden sind ähnlich, werden jedoch in unterschiedlichen Szenarien verwendet. .ToLookup()Gibt ein gebrauchsfertiges Objekt zurück, in dem bereits alle Gruppen (aber nicht der Inhalt der Gruppe) eifrig geladen sind. Gibt andererseits .GroupBy()eine verzögert geladene Folge von Gruppen zurück.

Verschiedene LINQ-Anbieter können unterschiedliche Verhaltensweisen für das eifrige und verzögerte Laden der Gruppen aufweisen. Mit LINQ-to-Object macht es wahrscheinlich wenig Unterschied, aber mit LINQ-to-SQL (oder LINQ-to-EF usw.) wird der Gruppierungsvorgang eher auf dem Datenbankserver als auf dem Client ausgeführt eine zusätzliche Filterung für den Gruppenschlüssel durchführen (der eine HAVINGKlausel generiert ) und dann nur einige der Gruppen anstelle aller abrufen. .ToLookup()würde eine solche Semantik nicht zulassen, da alle Elemente eifrig gruppiert sind.

Allon Guralnek
quelle