Pourquoi ToLookup et GroupBy sont-ils différents?

111

.ToLookup<TSource, TKey>renvoie un ILookup<TKey, TSource>. ILookup<TKey, TSource>implémente également l'interface IEnumerable<IGrouping<TKey, TSource>>.

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

ILookup a la propriété d'indexation pratique, donc il peut être utilisé d'une manière de type dictionnaire (ou de recherche), contrairement à GroupBy. GroupBy sans l'indexeur est difficile à utiliser; à peu près le seul moyen de référencer l'objet de retour est de le parcourir en boucle (ou d'utiliser une autre méthode d'extension LINQ). En d'autres termes, dans tous les cas où GroupBy fonctionne, ToLookup fonctionnera également.

Tout cela me laisse avec la question pourquoi devrais-je jamais m'embêter avec GroupBy? Pourquoi devrait-il exister?

Shlomo
la source
7
GroupByEst IQuerable, ILookupn'est pas
Magnus
5
GroupBy n'énumère pas la liste ToLookup l' énumère de la même manière ToList / ToArray
Aducci
3
Je l'ai proposé pour sa réouverture car la question dont il est prétendument dupliqué concerne IGrouping plutôt que GroupBy et ILookup plutôt que ToLookup . Les différences entre celles-ci sont différentes des différences entre celles-ci. Cela devrait ressortir des différences de réponses entre les questions.
Sam
1
les deux créent un Lookup, mais le GroupBycrée lorsque le résultat est énuméré referencesource.microsoft.com/#System.Core/System/Linq/...
Slai

Réponses:

175

pourquoi devrais-je me soucier de GroupBy? Pourquoi devrait-il exister?

Que se passe-t-il lorsque vous appelez ToLookup sur un objet représentant une table de base de données distante contenant un milliard de lignes?

Le milliard de lignes est envoyé sur le fil et vous créez la table de recherche localement.

Que se passe-t-il lorsque vous appelez GroupBy sur un tel objet?

Un objet de requête est construit; fin de l'histoire.

Lorsque cet objet de requête est énuméré, l'analyse de la table est effectuée sur le serveur de base de données et les résultats groupés sont renvoyés à la demande quelques uns à la fois.

Il s'agit logiquement de la même chose, mais les implications de chacun sur les performances sont complètement différentes. Appeler ToLookup signifie que je veux un cache de la chose entière maintenant organisé par groupe . Appeler GroupBy signifie "Je construis un objet pour représenter la question" à quoi ressembleraient ces choses si je les organisais par groupe? ""

Eric Lippert
la source
6
L'affiche ne cible pas spécifiquement une IQueryable<T>représentation. Votre réponse couvre cette situation, mais quand c'est tout simplement ol IEnumerable<T>(LINQ-to-Objects), il peut sembler qu'il n'y a pas de raison d'utiliser l'un par rapport à l'autre, ce que je crois que @Shlomo essaie de faire. Pas le IQueryable<T>cas, mais le cas LINQ-to-Objects.
casperOne
21
@casperOne: Je pense que vous n'avez pas compris mon point. Même dans le cas LINQ-to-objects, l'appel de GroupBy n'itère toujours pas sur la collection. (Comme Aducci l'a souligné dans la réponse que vous avez supprimée.) C'est une différence fondamentale.
Eric Lippert
12
@EricLippert: Mais est-ce juste un effet secondaire de l'implémentation ou est-il garanti que l'énumérable sera itéré lorsque vous appelez ToLookup, quelles que soient les modifications apportées à l'implémentation?
9
@Will: Vous faites un excellent point; la documentation ne garantit pas que ToLookup est "impatient". Il devrait probablement le noter.
Eric Lippert
10
Eagerness l'explique. Le langage de «ToMetaType», je pense, implique l'empressement; bien qu'il soit évidemment laissé à la mise en œuvre. Les autres «To» sont tous impatients (ToList, ToArray, ToDictionary). Merci les gars.
Shlomo
98

En termes simples du monde LINQ:

  • ToLookup() - exécution immédiate
  • GroupBy() - exécution différée
sll
la source
17

Les deux sont similaires, mais sont utilisés dans des scénarios différents. .ToLookup()renvoie un objet prêt à l'emploi qui a déjà tous les groupes (mais pas le contenu du groupe) chargés avec impatience. D'autre part, .GroupBy()renvoie une séquence de groupes chargée différemment.

Différents fournisseurs LINQ peuvent avoir des comportements différents pour le chargement hâtif et paresseux des groupes. Avec LINQ-to-Object, cela fait probablement peu de différence, mais avec LINQ-to-SQL (ou LINQ-to-EF, etc.), l'opération de regroupement est effectuée sur le serveur de base de données plutôt que sur le client, et vous voudrez peut-être pour effectuer un filtrage supplémentaire sur la clé de groupe (qui génère une HAVINGclause) et n'obtenir que certains des groupes au lieu de tous. .ToLookup()ne permettrait pas une telle sémantique puisque tous les éléments sont regroupés avec empressement.

Allon Guralnek
la source