Entendendo LINQ #2: Como usar o GroupBy

Jéferson Bueno
CWI Software
Published in
3 min readJul 18, 2019

Hey, se você caiu aqui de paraquedas, esta é uma sequência de outro post

O método GroupBy serve para agrupar elementos de uma coleção de acordo com um determinado valor (ou conjunto de valores) comum a eles e seu funcionamento é análogo à cláusula GROUP BY dos bancos de dados relacionais.

O GroupBy divide uma coleção em um grupo de coleções menores de acordo com o “critério de agrupamento” informado por parâmetro. De forma geral, os agrupamentos têm como propósito realizar uma ou mais agregações em cada grupo.

A primeira coisa que é preciso entender é como funciona a principal estrutura de retorno do método.

IEnumerable<IGrouping<TKey, TSource>>

Vendo a assinatura acima nota-se que o método irá retornar uma coleção de IGrouping's. Mas o que é este IGrouping?

IGrouping é uma interface que herda de IEnumerable, portanto ela é também um enumerável, uma coleção. Isso quer dizer que o método retorna uma coleção de coleções, ou melhor, uma coleção de grupos. A definição desta interface é a seguinte:

interface IGrouping<out TKey, out TElement>: IEnumerable<TElement> 
{
TKey Key { get; }
}

Cada grupo vai conter todos os elementos que atendam ao mesmo critério de agrupamento e também uma propriedade Key que carregará o valor (ou valores) em comum entre estes elementos.

Por exemplo: Ao agrupar uma lista de compras pelo mês da compra utilizando o GroupBy, o retorno será uma nova coleção com todos os grupos de compras para cada mês diferente.

Para efeito de comparação, é possível pensar nesta estrutura como um dicionário onde os elementos sejam coleções (listas, arrays, entre outros).

IDictionary<TipoChave, IEnumerable<TipoElemento>>

É importante ter em mente que, diferentemente de um dicionário, os grupos não contêm uma propriedade Value.

Code time

Primeiro, vamos usar uma classe Compra e criar um array de compras com alguns dados.

Como dito anteriormente, é possível agrupar as compras pelo mês da compra. Veja o código abaixo.

Veja funcionando no repl.it

Também é possível agrupar as compras pelo cliente.

Veja funcionando no repl.it

No código acima, fica claro que o retorno do GroupBy é uma coleção (IEnumerable) de IGrouping. Ou seja, cada elemento desta coleção é uma outra coleção formada pelo conjunto de todos os elementos da coleção original que atendem um mesmo critério de agrupamento, a propriedade Key é justamente o valor deste critério de agrupamento.

A tabela abaixo ilustra como ficam os dados na variável grupos para os dois códigos.

Ilustração das estruturas de agrupamento retornas pelo GroupBy

Agregações

Como dito no início, é bem comum se agrupar dados para aplicar funções de agregação nestes grupos. Com LINQ, é muito simples fazer estas agregações.

No código abaixo, é produzida uma nova coleção contendo algumas informações através das funções de agregação.

Veja funcionando no repl.it

É importante notar que gp é também uma coleção, portanto é possível filtrá-la usando Where, fazer projeções usando Select, etc.

O código abaixo filtra por clientes que tenham mais de uma compra e, na projeção, a propriedade PiorCompra representa a pior compra (a com menor valor) acima de $ 150.

Veja funcionando no repl.it

Da mesma forma, também é possível aninhar agrupamentos, produzindo resultados mais complexos.

Pra finalizar, veja o código abaixo. Nele a lista de compras é agrupada pelo mês da compra e, posteriormente, nos grupos de cada mês, é feito um segundo agrupamento pelo cliente da compra. Além disso, para cada agrupamento (tanto por mês, quanto por cliente) são adicionadas informações extras como a quantidade, o total em compras e o maior valor dentre as compras.

Veja funcionando no repl.it

O código dos exemplos pode ser executado e editado no Repl.it

--

--

Jéferson Bueno
CWI Software

Desenvolvo umas paradas na CWI Software e coleciono medalhas do Stack Overflow em Português. Eu sou o LINQ! — https://pt.stackoverflow.com/u/18246