152

.ToLookup<TSource, TKey> returns an ILookup<TKey, TSource>. ILookup<TKey, TSource> also implements interface IEnumerable<IGrouping<TKey, TSource>>.

.GroupBy<TSource, TKey> returns an IEnumerable<IGrouping<Tkey, TSource>>.

ILookup has the handy indexer property, so it can be used in a dictionary-like (or lookup-like) manner, whereas GroupBy can't. GroupBy without the indexer is a pain to work with; pretty much the only way you can then reference the return object is by looping through it (or using another LINQ-extension method). In other words, any case that GroupBy works, ToLookup will work as well.

All this leaves me with the question why would I ever bother with GroupBy? Why should it exist?

Jon
  • 9,156
  • 9
  • 56
  • 73
Shlomo
  • 14,102
  • 3
  • 28
  • 43
  • 13
    `GroupBy` Is `IQuerable`, `ILookup` is not – Magnus Apr 18 '12 at 18:19
  • 10
    GroupBy doesn't enumerate the list [ToLookup](http://msdn.microsoft.com/en-us/library/system.linq.enumerable.tolookup.aspx) enumerates it the same way ToList / ToArray – Aducci Apr 18 '12 at 18:19
  • 3
    I've nominated this for reopening since the question it's allegedly a duplicate of is about *IGrouping* rather than *GroupBy* and *ILookup* rather than *ToLookup*. The differences between those are different to the differences between these. This should be apparent from the differences in the answers between the questions. – Sam Jan 14 '15 at 01:16
  • 1
    both of them create a `Lookup`, but `GroupBy` creates it when the result is enumerated https://referencesource.microsoft.com/#System.Core/System/Linq/Enumerable.cs,d60d1015ac88b667 – Slai Oct 17 '16 at 01:21

3 Answers3

219

why would I ever bother with GroupBy? Why should it exist?

What happens when you call ToLookup on an object representing a remote database table with a billion rows in it?

The billion rows are sent over the wire, and you build the lookup table locally.

What happens when you call GroupBy on such an object?

A query object is built; end of story.

When that query object is enumerated then the analysis of the table is done on the database server and the grouped results are sent back on demand a few at a time.

Logically they are the same thing but the performance implications of each are completely different. Calling ToLookup means I want a cache of the entire thing right now organized by group. Calling GroupBy means "I am building an object to represent the question 'what would these things look like if I organized them by group?'"

casperOne
  • 73,706
  • 19
  • 184
  • 253
Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • 8
    The poster doesn't specifically target an `IQueryable` representation. Your answer covers that situation, but when it's just plain ol `IEnumerable` (LINQ-to-Objects) it can seem like there isn't a reason to use one over the other, which is what I believe @Shlomo is trying to get at. *Not* the `IQueryable` case, but the LINQ-to-Objects case. – casperOne Apr 18 '12 at 18:33
  • It strikes me as beneficial for LINQ to be consistent, where possible. I think demonstrating its usefulness in LINQ-to-SQL is sufficient to justify leaving it in LINQ-to-Objects. – Brian Apr 18 '12 at 19:14
  • 24
    @casperOne: I think you've failed to understand my point. Even in the LINQ-to-objects case, calling GroupBy *still* does not iterate over the collection. (As Aducci pointed out in the answer which you deleted.) That's a fundamental difference. – Eric Lippert Apr 18 '12 at 19:42
  • @EricLippert Fair enough, admittedly, I completely missed this. Brain expulsion. – casperOne Apr 18 '12 at 19:44
  • 13
    @EricLippert: But is that just a side effect of the implementation or is it *guaranteed* that the enumerable will be iterated when you call ToLookup, no matter what changes are made to the implementation? –  Apr 18 '12 at 19:53
  • 11
    @Will: You make an excellent point; the documentation does not guarantee that ToLookup is "eager". It probably should note that. – Eric Lippert Apr 18 '12 at 20:20
  • 17
    Eagerness explains it. The language of 'ToMetaType' I think implies eagerness; though it is obviously left up to the implementation. The other 'To's are all eager (ToList, ToArray, ToDictionary). Thanks guys. – Shlomo Apr 18 '12 at 22:31
131

In simple LINQ-world words:

  • ToLookup() - immediate execution
  • GroupBy() - deferred execution
Lance Roberts
  • 22,383
  • 32
  • 112
  • 130
sll
  • 61,540
  • 22
  • 104
  • 156
21

The two are similar, but are used in different scenarios. .ToLookup() returns a ready to use object that already has all the groups (but not the group's content) eagerly loaded. On the other hand, .GroupBy() returns a lazy loaded sequence of groups.

Different LINQ providers may have different behaviors for the eager and lazy loading of the groups. With LINQ-to-Object it probably makes little difference, but with LINQ-to-SQL (or LINQ-to-EF, etc.), the grouping operation is performed on the database server rather than the client, and so you may want to do an additional filtering on the group key (which generates a HAVING clause) and then only get some of the groups instead of all of them. .ToLookup() wouldn't allow for such semantics since all items are eagerly grouped.

Allon Guralnek
  • 15,813
  • 6
  • 60
  • 93