Perché ToLookup e GroupBy sono diversi?


111

.ToLookup<TSource, TKey>restituisce un ILookup<TKey, TSource>. ILookup<TKey, TSource>implementa anche l'interfaccia IEnumerable<IGrouping<TKey, TSource>>.

.GroupBy<TSource, TKey>restituisce un IEnumerable<IGrouping<Tkey, TSource>>.

ILookup ha la pratica proprietà indicizzatore, quindi può essere utilizzato in un modo simile a un dizionario (o simile a una ricerca), mentre GroupBy non può. GroupBy senza l'indicizzatore è un problema con cui lavorare; praticamente l'unico modo in cui è possibile fare riferimento all'oggetto restituito è eseguendo un ciclo attraverso di esso (o utilizzando un altro metodo di estensione LINQ). In altre parole, in ogni caso in cui GroupBy funzioni, anche ToLookup funzionerà.

Tutto questo mi lascia con la domanda perché dovrei mai preoccuparmi di GroupBy? Perché dovrebbe esistere?


7
GroupByÈ IQuerable, ILookupnon è
Magnus

5
GroupBy non enumera l'elenco ToLookup lo enumera allo stesso modo ToList / ToArray
Aducci

3
L'ho nominato per la riapertura poiché la domanda di cui è presumibilmente un duplicato riguarda IGrouping piuttosto che GroupBy e ILookup piuttosto che ToLookup . Le differenze tra questi sono diverse dalle differenze tra questi. Ciò dovrebbe essere evidente dalle differenze nelle risposte tra le domande.
Sam

1
entrambi creano un Lookup, ma lo GroupBycreano quando il risultato è enumerato. referencesource.microsoft.com/#System.Core/System/Linq/…
Slai

Risposte:


175

perché dovrei mai preoccuparmi di GroupBy? Perché dovrebbe esistere?

Cosa succede quando chiami ToLookup su un oggetto che rappresenta una tabella di database remoto con un miliardo di righe al suo interno?

I miliardi di righe vengono inviati in rete e la tabella di ricerca viene creata localmente.

Cosa succede quando chiami GroupBy su un oggetto del genere?

Viene creato un oggetto query; fine della storia.

Quando l'oggetto di query viene enumerato, l'analisi della tabella viene eseguita sul server del database e i risultati raggruppati vengono restituiti su richiesta pochi alla volta.

Logicamente sono la stessa cosa ma le implicazioni prestazionali di ciascuna sono completamente diverse. Chiamare ToLookup significa che voglio una cache dell'intera cosa in questo momento organizzata per gruppo . Chiamare GroupBy significa "Sto costruendo un oggetto per rappresentare la domanda 'come sarebbero queste cose se le organizzassi per gruppo?'"


6
Il poster non mira specificamente a una IQueryable<T>rappresentazione. La tua risposta copre questa situazione, ma quando è semplicemente ol IEnumerable<T>(LINQ-to-Objects) può sembrare che non ci sia un motivo per usarne uno sull'altro, che è ciò che credo che @Shlomo stia cercando di ottenere. Non il IQueryable<T>caso, ma il caso LINQ-to-Objects.
casperOne

21
@casperOne: Penso che tu non abbia capito il mio punto. Anche nel caso LINQ to-oggetti, chiamando GroupBy ancora non iterare sulla raccolta. (Come ha sottolineato Aducci nella risposta che hai cancellato). Questa è una differenza fondamentale.
Eric Lippert

12
@EricLippert: Ma è solo un effetto collaterale dell'implementazione o è garantito che l'enumerabile verrà ripetuto quando chiami ToLookup, indipendentemente dalle modifiche apportate all'implementazione?

9
@ Will: fai un'ottima osservazione; la documentazione non garantisce che ToLookup sia "desideroso". Probabilmente dovrebbe tenerne conto.
Eric Lippert

10
L'entusiasmo lo spiega. Il linguaggio di "ToMetaType" penso implichi entusiasmo; sebbene sia ovviamente lasciata all'implementazione. Gli altri "To" sono tutti entusiasti (ToList, ToArray, ToDictionary). Grazie ragazzi.
Shlomo

98

In semplici parole del mondo LINQ:

  • ToLookup() - esecuzione immediata
  • GroupBy() - esecuzione differita

17

I due sono simili, ma vengono utilizzati in scenari diversi. .ToLookup()restituisce un oggetto pronto per l'uso che ha già caricato tutti i gruppi (ma non il contenuto del gruppo). D'altra parte, .GroupBy()restituisce una sequenza di gruppi caricata in modo pigro.

Diversi provider LINQ possono avere comportamenti diversi per il caricamento desideroso e lento dei gruppi. Con LINQ-to-Object probabilmente fa poca differenza, ma con LINQ-to-SQL (o LINQ-to-EF, ecc.), L'operazione di raggruppamento viene eseguita sul server di database anziché sul client, quindi potresti volere per eseguire un filtro aggiuntivo sulla chiave del gruppo (che genera una HAVINGclausola) e quindi ottenere solo alcuni dei gruppi invece di tutti. .ToLookup()non consentirebbe tale semantica poiché tutti gli elementi sono raggruppati con entusiasmo.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.