Por que ToLookup e GroupBy são diferentes?


111

.ToLookup<TSource, TKey>retorna um ILookup<TKey, TSource>. ILookup<TKey, TSource>também implementa interface IEnumerable<IGrouping<TKey, TSource>>.

.GroupBy<TSource, TKey>retorna um IEnumerable<IGrouping<Tkey, TSource>>.

ILookup tem a propriedade indexer útil, portanto, pode ser usado de maneira semelhante a um dicionário (ou semelhante a uma consulta), enquanto o GroupBy não pode. O GroupBy sem o indexador é difícil de trabalhar; praticamente a única maneira de fazer referência ao objeto de retorno é fazendo um loop por ele (ou usando outro método de extensão LINQ). Em outras palavras, em qualquer caso em que GroupBy funcione, ToLookup funcionará também.

Tudo isso me deixa com a pergunta: por que eu deveria me preocupar com o GroupBy? Por que deveria existir?


7
GroupByÉ IQuerable, ILookupnão é
Magnus

5
GroupBy não enumera a lista ToLookup enumera da mesma maneira ToList / ToArray
Aducci

3
Eu indiquei isso para reabertura, pois a pergunta que é supostamente uma duplicata é sobre IGrouping em vez de GroupBy e ILookup em vez de ToLookup . As diferenças entre eles são diferentes das diferenças entre eles. Isso deve ser aparente a partir das diferenças nas respostas entre as perguntas.
Sam

1
ambos criam um Lookup, mas o GroupBycria quando o resultado é enumerado referenceource.microsoft.com/#System.Core/System/Linq/…
Slai

Respostas:


175

por que eu iria me preocupar com GroupBy? Por que deveria existir?

O que acontece quando você chama ToLookup em um objeto que representa uma tabela de banco de dados remoto com um bilhão de linhas?

O bilhão de linhas é enviado pela rede e você constrói a tabela de pesquisa localmente.

O que acontece quando você chama GroupBy em um objeto assim?

Um objeto de consulta é construído; fim da história.

Quando esse objeto de consulta é enumerado, a análise da tabela é feita no servidor de banco de dados e os resultados agrupados são enviados de volta sob demanda, alguns de cada vez.

Logicamente, eles são a mesma coisa, mas as implicações de desempenho de cada um são completamente diferentes. Chamar ToLookup significa que quero um cache de tudo agora organizado por grupo . Chamar GroupBy significa "Estou construindo um objeto para representar a pergunta 'como seriam essas coisas se eu as organizasse em grupos?'"


6
O pôster não visa especificamente uma IQueryable<T>representação. Sua resposta cobre essa situação, mas quando é simples IEnumerable<T>(LINQ-to-Objects) pode parecer que não há motivo para usar um em vez do outro, que é o que acredito que @Shlomo está tentando chegar. Não é o IQueryable<T>caso, mas o caso LINQ-to-Objects.
casperOne

21
@casperOne: Acho que você não entendeu meu ponto. Mesmo no caso do LINQ para objetos, chamar GroupBy ainda não itera na coleção. (Como Aducci apontou na resposta que você excluiu.) Essa é uma diferença fundamental.
Eric Lippert de

12
@EricLippert: Mas isso é apenas um efeito colateral da implementação ou é garantido que o enumerável será iterado quando você chamar ToLookup, não importa quais alterações sejam feitas na implementação?

9
@Will: Você fez uma observação excelente; a documentação não garante que ToLookup esteja "ansioso". Provavelmente deve notar isso.
Eric Lippert de

10
A ansiedade explica isso. A linguagem de 'ToMetaType' eu acho que implica ansiedade; embora seja obviamente deixado para a implementação. Os outros 'To's estão todos ansiosos (ToList, ToArray, ToDictionary). Obrigado rapazes.
Shlomo

98

Em palavras simples do mundo LINQ:

  • ToLookup() - execução imediata
  • GroupBy() - execução adiada

17

Os dois são semelhantes, mas são usados ​​em cenários diferentes. .ToLookup()retorna um objeto pronto para usar que já possui todos os grupos (mas não o conteúdo do grupo) carregados avidamente. Por outro lado, .GroupBy()retorna uma sequência de grupos carregada lentamente.

Diferentes provedores de LINQ podem ter comportamentos diferentes para o carregamento rápido e lento dos grupos. Com LINQ-to-Object provavelmente faz pouca diferença, mas com LINQ-to-SQL (ou LINQ-to-EF, etc.), a operação de agrupamento é realizada no servidor de banco de dados em vez do cliente e, portanto, você pode desejar para fazer uma filtragem adicional na chave do grupo (o que gera uma HAVINGcláusula) e então obter apenas alguns dos grupos em vez de todos eles. .ToLookup()não permitiria tal semântica, uma vez que todos os itens são agrupados avidamente.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.