Dlaczego toLookup i GroupBy są różne?

111

.ToLookup<TSource, TKey>zwraca plik ILookup<TKey, TSource>. ILookup<TKey, TSource>implementuje również interfejs IEnumerable<IGrouping<TKey, TSource>>.

.GroupBy<TSource, TKey>zwraca plik IEnumerable<IGrouping<Tkey, TSource>>.

ILookup ma przydatną właściwość indeksatora, więc może być używana w sposób podobny do słownika (lub podobny do wyszukiwania), podczas gdy GroupBy nie może. GroupBy bez indeksatora to uciążliwa praca; właściwie jedynym sposobem, w jaki możesz odwołać się do zwracanego obiektu, jest przejście przez niego (lub użycie innej metody rozszerzenia LINQ). Innymi słowy, w każdym przypadku, gdy działa GroupBy, ToLookup również będzie działać.

Wszystko to pozostawia mi pytanie, dlaczego miałbym kiedykolwiek zawracać sobie głowę GroupBy? Dlaczego miałoby istnieć?

Szlomo
źródło
7
GroupByJest IQuerable, ILookupnie jest
Magnus
5
GroupBy nie wyliczać listy ToLookup wymienia go w ten sam sposób ToList / ToArray
Aducci
3
Nominowałem to do ponownego otwarcia, ponieważ pytanie, które rzekomo jest duplikatem, dotyczy raczej IGrouping niż GroupBy i ILookup, a nie ToLookup . Różnice między nimi są inne niż różnice między nimi. Powinno to wynikać z różnic w odpowiedziach między pytaniami.
Sam,
1
oba tworzą Lookup, ale GroupBytworzy je, gdy wynik jest wyliczany referencjeource.microsoft.com/#System.Core/System/Linq/…
Slai

Odpowiedzi:

175

dlaczego miałbym kiedykolwiek zawracać sobie głowę GroupBy? Dlaczego miałoby istnieć?

Co się dzieje, gdy wywołujesz ToLookup na obiekcie reprezentującym zdalną tabelę bazy danych z miliardem wierszy?

Miliard wierszy jest przesyłanych przez sieć, a Ty lokalnie tworzysz tabelę przeglądową.

Co się dzieje, gdy wywołujesz GroupBy na takim obiekcie?

Budowany jest obiekt zapytania; Koniec opowieści.

Po wyliczeniu tego obiektu zapytania analiza tabeli jest wykonywana na serwerze bazy danych, a zgrupowane wyniki są odsyłane na żądanie po kilka na raz.

Logicznie rzecz biorąc, to to samo, ale implikacje wydajnościowe każdego z nich są zupełnie inne. Wywołanie ToLookup oznacza, że chcę teraz mieć pamięć podręczną całej rzeczy zorganizowaną według grup . Wywołanie GroupBy oznacza „Buduję obiekt, który ma odpowiadać pytaniu 'jak te rzeczy wyglądałyby, gdybym je uporządkował według grup?'”

Eric Lippert
źródło
6
Plakat nie jest konkretnie ukierunkowany na IQueryable<T>przedstawienie. Twoja odpowiedź obejmuje tę sytuację, ale kiedy jest po prostu ol IEnumerable<T>(LINQ-to-Objects), może się wydawać, że nie ma powodu, aby używać jednego nad drugim, do czego, jak sądzę, próbuje dotrzeć @Shlomo. Nie jest to IQueryable<T>przypadek, ale przypadek LINQ-to-Objects.
casperOne
21
@casperOne: Myślę, że nie zrozumiałeś mojego punktu widzenia. Nawet w przypadku LINQ-to-objects wywołanie GroupBy nadal nie wykonuje iteracji po kolekcji. (Jak wskazał Aducci w odpowiedzi, którą usunąłeś). To podstawowa różnica.
Eric Lippert
12
@EricLippert: Ale czy to tylko efekt uboczny implementacji, czy też jest zagwarantowane, że wyliczalne zostanie iterowane po wywołaniu ToLookup, bez względu na to, jakie zmiany zostaną wprowadzone w implementacji?
9
@Will: Masz świetną uwagę; dokumentacja nie gwarantuje, że ToLookup jest „chętny”. Powinien to chyba zauważyć.
Eric Lippert
10
Chęć to wyjaśnia. Myślę, że język „ToMetaType” sugeruje chęć; choć oczywiście jest to pozostawione wdrożeniu. Pozostałe „To” są chętne (ToList, ToArray, ToDictionary). Dzięki chłopaki.
Shlomo
98

W prostych słowach świata LINQ:

  • ToLookup() - natychmiastowa realizacja
  • GroupBy() - wykonanie odroczone
sll
źródło
17

Oba są podobne, ale są używane w różnych scenariuszach. .ToLookup()zwraca gotowy do użycia obiekt, który ma już wszystkie grupy (ale nie zawartość grupy), które zostały chętnie załadowane. Z drugiej strony,.GroupBy() zwraca leniwie ładowaną sekwencję grup.

Różni dostawcy LINQ mogą mieć różne zachowania dla chętnego i leniwego ładowania grup. W przypadku LINQ-to-Object prawdopodobnie robi to niewielką różnicę, ale w przypadku LINQ-to-SQL (lub LINQ-to-EF itp.) Operacja grupowania jest wykonywana na serwerze bazy danych, a nie na kliencie, więc możesz chcieć wykonać dodatkowe filtrowanie na kluczu grupy (który generuje HAVINGklauzulę), a następnie pobrać tylko niektóre grupy zamiast wszystkich. .ToLookup()nie pozwoliłby na taką semantykę, ponieważ wszystkie elementy są chętnie grupowane.

Allon Guralnek
źródło