Почему ToLookup и GroupBy разные?

111

.ToLookup<TSource, TKey>возвращает ILookup<TKey, TSource>. ILookup<TKey, TSource>также реализует интерфейс IEnumerable<IGrouping<TKey, TSource>>.

.GroupBy<TSource, TKey>возвращает IEnumerable<IGrouping<Tkey, TSource>>.

ILookup имеет удобное свойство индексатора, поэтому его можно использовать в манере словаря (или поиска), тогда как GroupBy - нет. GroupBy без индексатора затрудняет работу; практически единственный способ ссылаться на возвращаемый объект - это перебрать его (или использовать другой метод расширения LINQ). Другими словами, в любом случае, если GroupBy работает, ToLookup также будет работать.

Все это оставляет меня с вопросом, зачем мне вообще заниматься GroupBy? Почему он должен существовать?

Шломо
источник
7
GroupByЕсть IQuerable, ILookupнет
Магнус
5
GroupBy не перечисляет список ToLookup перечисляет его так же, как ToList / ToArray
Адуччи
3
Я назначил его для повторного открытия, поскольку вопрос, который якобы дублирует, касается IGrouping, а не GroupBy и ILookup, а не ToLookup . Различия между ними отличаются от различий между ними. Это должно быть очевидно из различий в ответах между вопросами.
Сэм
1
оба они создают Lookup, но GroupByсоздают его, когда результат перечисляется ссылкамиource.microsoft.com
System.Core/System/Linq/…

Ответы:

175

зачем мне вообще беспокоиться о GroupBy? Почему он должен существовать?

Что происходит, когда вы вызываете ToLookup для объекта, представляющего таблицу удаленной базы данных с миллиардом строк в ней?

Миллиард строк отправляется по сети, и вы создаете таблицу поиска локально.

Что происходит, когда вы вызываете GroupBy для такого объекта?

Создается объект запроса; конец истории.

Когда этот объект запроса перечисляется, анализ таблицы выполняется на сервере базы данных, и сгруппированные результаты отправляются обратно по запросу по несколько раз.

Логически это одно и то же, но влияние каждого на производительность совершенно разное. Вызов ToLookup означает, что я хочу, чтобы прямо сейчас кэш был организован по группам . Вызов GroupBy означает: «Я создаю объект для представления вопроса:« Как бы эти вещи выглядели, если бы я организовал их по группам? »»

Эрик Липперт
источник
6
Плакат специально не нацелен на IQueryable<T>представление. Ваш ответ охватывает эту ситуацию, но когда это просто ol IEnumerable<T>(LINQ-to-Objects), может показаться, что нет причин использовать одно вместо другого, что, как я считаю, пытается достичь @Shlomo. Не тот IQueryable<T>случай, а случай LINQ-to-Objects.
casperOne
21
@casperOne: Думаю, вы не поняли мою точку зрения. Даже в случае LINQ-to-objects вызов GroupBy по- прежнему не выполняет итерацию по коллекции. (Как указал Адуччи в ответе, который вы удалили.) Это фундаментальная разница.
Эрик Липперт
12
@EricLippert: Но является ли это побочным эффектом реализации или гарантируется, что перечисляемое будет повторяться при вызове ToLookup, независимо от того, какие изменения были внесены в реализацию?
9
@Will: Вы прекрасно замечаете; документация не гарантирует, что ToLookup «готов». Вероятно, следует отметить это.
Эрик Липперт
10
Это объясняет рвение. Я думаю, что язык ToMetaType подразумевает рвение; хотя, очевидно, это оставлено на усмотрение реализации. Все остальные «Кому» (ToList, ToArray, ToDictionary) стремятся. Спасибо, парни.
Шломо
98

Простыми словами LINQ-world:

  • ToLookup() - немедленное исполнение
  • GroupBy() - отсроченное исполнение
SLL
источник
17

Они похожи, но используются в разных сценариях. .ToLookup()возвращает готовый к использованию объект, в котором уже загружены все группы (но не содержимое группы). С другой стороны, .GroupBy()возвращает ленивую последовательность групп.

У разных поставщиков LINQ может быть разное поведение для быстрой и отложенной загрузки групп. С LINQ-to-Object это, вероятно, не имеет большого значения, но с LINQ-to-SQL (или LINQ-to-EF и т. Д.) Операция группировки выполняется на сервере базы данных, а не на клиенте, поэтому вы можете захотеть чтобы выполнить дополнительную фильтрацию по ключу группы (который генерирует HAVINGпредложение), а затем получить только некоторые из групп вместо всех. .ToLookup()не допускает такой семантики, поскольку все элементы сгруппированы с готовностью.

Аллон Гуралнек
источник