.NET 9.0  -  Novos métodos da LINQ


   Neste artigo vou apresentar os novos métodos da LINQ disponíveis com lançamento da versão do .NET 9.0 SDK.

Para experimentar esses recursos você precisará da versão mais recente do Visual Studio 2022 e do .NET 9 SDK.

Três novos métodos foram adicionados ao arsenal da LINQ :  CountBy, AggregateBy e Index.

Eles são projetados para melhorar o desempenho e a concisão em tarefas comuns de manipulação de dados. Vamos apresentar a seguir cada um deles.

1- CountBy

O método CountBy é ideal para contagem de elementos em uma sequência, agrupando-os por uma determinada chave. Ele retorna um dicionário onde as chaves são os valores únicos da propriedade especificada e os valores são as contagens correspondentes.

Desta forma o método CountBy agrupa elementos de uma coleção e retorna um IEnumerable de pares chave-valor, onde a chave é o elemento agrupado e o valor é a contagem de ocorrências.

Exemplo:

(string nome, string sobrenome)[] pessoas =
[
   ("João", "Donato"),
   ("Janice", "Silva"),
   ("João", "Sanches"),
   ("Maria", "Silveira"),
   ("Pedro", "Sobrinho"),
   ("Janice", "Fernandez"),
   ("Maria", "Moretii")
]; 

Este código cria um array de tuplas onde cada tupla contém dois elementos do tipo string:

nome: Representa o primeiro elemento da tupla.
sobrenome
: Representa o segundo elemento da tupla.

Como eu poderia conter quantas vezes cada nome aparece na lista ?

Antes do C# 13 poderíamos usar este código:

var contaNomes = pessoas
   .GroupBy(p => p.nome)
   .ToDictionary(group => group.Key, group => group.Count())
   .AsEnumerable();
foreach (var entry in contaNomes)
{
    Console.WriteLine($"O Nome {entry.Key} aparece {entry.Value} vezes");
}

A partir do .NET 9.0 pode simplificar o código usando o método CountBy :

(string nome, string sobrenome)[] pessoas =
[
   ("João", "Donato"),
   ("Janice", "Silva"),
   ("João", "Sanches"),
   ("Maria", "Silveira"),
   ("Pedro", "Sobrinho"),
   ("Janice", "Fernandez"),
   ("Maria", "Moretii")
];
// .NET 9
var contaNomes = pessoas
   .CountBy(p => p.nome);
foreach (var entry in contaNomes)
{
    Console.WriteLine($"O Nome {entry.Key} aparece {entry.Value} vezes");
}

O resultado obtido será o seguinte:

2- AggregateBy

O método AggregateBy permite realizar agregações em uma sequência, agrupando os elementos por uma chave e aplicando uma função de agregação em cada grupo. É como um GroupBy mais poderoso, pois permite personalizar a operação de agregação.

Assim o método AggregateBy permite agrupar elementos por uma chave e calcular valores relacionados à chave. É útil para somar, concatenar ou calcular médias agrupadas.

Exemplo:

(string nome, string departamento, int diasFerias)[] funcionarios =
[
   ("João Duda", "IT", 12),
   ("Jane Soares", "Marketing", 18),
   ("Jose Silva", "IT", 28),
   ("Maria Fernandez", "RH", 17),
   ("Nivia Maria", "Marketing", 5),
   ("Maria Moreti", "RH", 9)
];

Acima temos um array de tuplas onde cada tupla contém dois elementos do tipo string e um elemento do tipo int.

Como podemos agrupar o número restante de férias dos funcionários por departamento ?

Antes do .NET 9.0 podemos usar o seguinte´código:

// Antes do  NET 9.0
var diasFeriasDepartamento = funcionarios
   .GroupBy(funci => funci.departamento)
   .ToDictionary(group => group.Key, group => group.Sum(funci => funci.diasFerias))
   .AsEnumerable();
foreach (var entry in diasFeriasDepartamento)
    Console.WriteLine($"O Departamento {entry.Key} possui um total de {entry.Value} dias de férias a cumprir.");

 à abordaPodemos melhorar este código usando o método AggregateBy:

(string nome, string departamento, int diasFerias)[] funcionarios =
[
   ("João Duda", "IT", 12),
   ("Jane Soares", "Marketing", 18),
   ("Jose Silva", "IT", 28),
   ("Maria Fernandez", "RH", 17),
   ("Nivia Maria", "Marketing", 5),
   ("Maria Moreti", "RH", 9)
];
// .NET 9
var diasFeriasDepartamento = funcionarios
   .AggregateBy(emp => emp.departamento, 0, (acc, funci) => acc + funci.diasFerias);
foreach (var entry in diasFeriasDepartamento)
    Console.WriteLine($"O Departamento {entry.Key} possui um total de {entry.Value} dias de férias a cumprir.");
Console.ReadLine();

O resultado obtido será o seguinte:

3- Index

O método Index retorna o índice de um elemento em uma sequência, similar ao método IndexOf. No entanto, ele oferece mais flexibilidade, permitindo personalizar a comparação entre os elementos.

Assim o Index gera uma sequência de tuplas contendo o índice e o valor correspondente de uma coleção. Ele facilita acessar os índices diretamente enquanto itera sobre os elementos.

Exemplo:

var alunos = new[]
{
   "Jose Sanches",
   "Janice Pereira",
   "Carlos Nogueira",
   "João Silveira"
};

Dada uma lista de alunos, usando o .NET 8 ou anterior,  para obter os índices junto com os valores de uma coleção, você precisava usar o método Select combinando índices manualmente:

edades automáticas no C# 13 fornecem uma maneira mais simplificada de declarar propriedades sem campos de apoio explícitos.

var alunos = new[]
{
   "Jose Sanches",
   "Janice Pereira",
   "Carlos Nogueira",
   "João Silveira"
};
// antes
foreach (var (index, aluno) in alunos.Select((m, i) => (i, m)))
    Console.WriteLine($"Aluno {index}: {aluno}");
Console.ReadLine(); 

O Select é usado para projetar cada elemento (m) da coleção junto com seu índice (i) como uma tupla (i, m).

Isso adiciona uma camada de complexidade ao código, tornando-o menos legível.

A partir do .NET 9.0 o método Index simplifica esse processo, permitindo iterar diretamente sobre os valores e seus índices:

var alunos = new[]
{
   "Jose Sanches",
   "Janice Pereira",
   "Carlos Nogueira",
   "João Silveira"
};
// .NET 9
foreach (var (index, aluno) in alunos.Index())
    Console.WriteLine($"Aluno {index}: {aluno}");
Console.ReadLine(); 

O C# 13 in O método Index encapsula a lógica de emparelhamento de índices e valores, entregando uma API mais limpa e intuitiva.

É mais conciso e elimina a necessidade de usar o Select.

Resultado obtido:

O método Index no .NET 9 oferece uma maneira mais elegante e limpa para acessar índices de uma coleção ao iterar, sem alterar a funcionalidade. É um ótimo exemplo de como o .NET continua evoluindo para melhorar a experiência de desenvolvimento.

E estamos conversados...

"Ensina-me, Senhor, o teu caminho, e andarei na tua verdade; une o meu coração ao temor do teu nome."
Salmos 86:11

Referências:


José Carlos Macoratti