CodeGym /Cours /C# SELF /Nouvelles méthodes LINQ : ...

Nouvelles méthodes LINQ : CountBy et AggregateBy

C# SELF
Niveau 32 , Leçon 2
Disponible

1. Intro

Si t’as déjà écrit une requête LINQ "classique" avec un groupement, genre :


var cityCounts = students.GroupBy(s => s.City)
                         .Select(g => new { City = g.Key, Count = g.Count() });

t’as sûrement remarqué que pour juste compter par groupe, le code est un peu verbeux. Avec .NET 9, l’équipe Microsoft a voulu nous simplifier la vie et a ajouté deux méthodes super demandées dans LINQ :

  • CountBy — un moyen rapide de compter les éléments par clé.
  • AggregateBy — un agrégateur universel par clé (ça compte, ça fait la somme, etc.).

Au fait, ces méthodes sont là parce que la commu les réclamait à fond, et leurs équivalents existent depuis longtemps dans plein de libs LINQ "avancées", genre MoreLINQ.

2. La méthode CountBy : compter par groupe, easy

Description

CountBy, c’est littéralement "je groupe, puis je compte direct". Cette méthode te renvoie une collection de paires "clé-nombre", ce qui est super utile dans la vraie vie : top des villes, nombre d’étudiants par note, fréquence d’apparition de trucs, etc.

Signature (en mode simple) :


IEnumerable<(TKey Key, int Count)> CountBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)

Exemples concrets

Exemple 1 : Nombre d’étudiants par ville

Imaginons qu’on a cette classe :


class Student
{
    public string Name { get; set; }
    public int Grade { get; set; }
    public string City { get; set; }
}

Et dans notre appli — une liste d’étudiants :


var students = new List<Student>
{
    new Student { Name = "Ivan", Grade = 5, City = "Neonville" },
    new Student { Name = "Anna", Grade = 4, City = "Los-Santos" },
    new Student { Name = "Egor", Grade = 3, City = "Neonville" },
    new Student { Name = "Maria", Grade = 5, City = "Rosewater" },
    new Student { Name = "Oleg", Grade = 4, City = "Neonville" }
};

En .NET 8 et avant, fallait écrire :


var group = students.GroupBy(s => s.City)
                    .Select(g => new { City = g.Key, Count = g.Count() });

foreach (var cityInfo in group)
{
    Console.WriteLine($"{cityInfo.City}: {cityInfo.Count} étudiants");
}

En .NET 9, un seul appel suffit :


var cityCounts = students.CountBy(s => s.City);
foreach (var (city, count) in cityCounts)
{
    Console.WriteLine($"{city}: {count} étudiants");
}

Ouais, t’as bien vu — pas de GroupBy à la main, pas de Count() à calculer — c’est direct et clair !

Exemple 2 : Compter par note

Le truc classique pour un doyen — savoir combien de cracks et de cancres il y a dans le groupe :


var gradeCounts = students.CountBy(s => s.Grade);

foreach (var (grade, count) in gradeCounts)
{
    Console.WriteLine($"Note {grade}: {count} étudiants");
}

Exemple 3 : Fréquence des caractères dans une string

CountBy marche pas que sur des objets, mais aussi sur des trucs plus simples :


string word = "supercalifragilisticexpialidocious";
var charFrequencies = word.CountBy(ch => ch);

foreach (var (letter, count) in charFrequencies)
{
    Console.WriteLine($"{letter} : {count}");
}

Visu mémoire (illustration)

Clé Count (avant CountBy) Count (avec CountBy)
"Neonville"
3 3
"Rosewater"
1 1
"Los Santos"
1 1

Ce genre d’approche rend le code lisible et limite les bugs quand tu groupes.

Pièges et subtilités

N’oublie pas, CountBy te renvoie un tuple (Key, Count), pas un type anonyme. Parfois c’est un peu moins parlant, mais au moins c’est super clair. Aussi, tu peux pas choisir le type du nombre pour Count — c’est toujours un int.

3. La méthode AggregateBy : l’agrégateur universel

Description

Si CountBy c’est juste compter par clé, AggregateBy c’est le couteau suisse ! Tu veux la somme des ventes par vendeur, la note max par classe, ou n’importe quoi qui s’accumule ? AggregateBy fait tout ça.

Signature (en mode très simplifié) :


IEnumerable<(TKey Key, TAccumulate Result)> AggregateBy<TSource, TKey, TAccumulate>(
    this IEnumerable<TSource> source,
    Func<TSource, TKey> keySelector,
    TAccumulate seed,
    Func<TAccumulate, TSource, TAccumulate> func)
  • keySelector — sur quoi tu groupes.
  • seed — la valeur de départ pour l’accumulation.
  • func — la fonction qui dit comment "accumuler" le résultat.

Exemples concrets

Exemple 1 : Somme des notes par ville

Au lieu d’un LINQ bien lourd :


var sums = students.GroupBy(s => s.City)
                   .Select(g => new { City = g.Key, Sum = g.Sum(s => s.Grade) });

Tu fais :


var sums = students.AggregateBy(
    s => s.City, // on groupe par ville
    0,           // somme de départ
    (acc, s) => acc + s.Grade // on ajoute la note
);

foreach (var (city, sum) in sums)
{
    Console.WriteLine($"{city}: somme des notes = {sum}");
}

Exemple 2 : Note max par ville

Tu veux la valeur max ? Change juste l’accumulateur :


var maxByCity = students.AggregateBy(
    s => s.City,
    int.MinValue, // valeur de départ — le minimum possible
    (max, s) => Math.Max(max, s.Grade)
);
foreach (var (city, maxGrade) in maxByCity)
{
    Console.WriteLine($"{city}: note max = {maxGrade}");
}

Exemple 3 : On concatène les noms dans une string

On met à jour notre liste d’étudiants :


var namesByCity = students.AggregateBy(
    s => s.City,
    "", // string de départ
    (acc, s) => string.IsNullOrEmpty(acc) ? s.Name : acc + ", " + s.Name
);

foreach (var (city, names) in namesByCity)
{
    Console.WriteLine($"{city}: {names}");
}

Visu "sous le capot" (schéma)


.   {Student, Student, Student, ...}
               |
               | (on groupe par city)
               v
["Neonville"]  ["Rosewater"]  ["Los Santos"]
      |           |               |
      |     (accumulation)        |
      |___________________________|
            |
            v
{("Neonville", somme), ("Rosewater", somme), ...}

Comparé à l’ancienne méthode

Avant, pour tout ça, fallait faire GroupBy + Select, avec dedans un Sum, Aggregate ou un autre truc tordu. Maintenant AggregateBy cache toute cette "douleur" et rend le code court et expressif.

Pratique : on l’utilise dans l’appli

Notre projet d’école — un carnet de notes étudiants. On va ajouter un rapport sur la moyenne par ville.


// On calcule la moyenne avec AggregateBy — on accumule la somme et le nombre, puis on fait la moyenne
var avgByCity = students.AggregateBy(
    s => s.City,
    (Sum: 0, Count: 0),
    (acc, s) => (acc.Sum + s.Grade, acc.Count + 1)
).Select(x => (x.Key, Average: (double)x.Result.Sum / x.Result.Count));

foreach (var (city, avg) in avgByCity)
{
    Console.WriteLine($"{city}: moyenne = {avg:F2}");
}

Ici on accumule la somme et le nombre dans un tuple, puis on divise pour avoir la moyenne.

Spécificités et pièges

Si ton accumulateur est un type référence, fais gaffe : dans AggregateBy c’est la même référence pour toutes les itérations du groupe, donc évite de muter l’objet, sinon tu risques de pourrir le résultat du groupe.

Et aussi : si tu veux pas juste grouper mais aussi transformer le résultat — tu peux direct utiliser .Select. Choisis bien ton seed (valeur de départ), sinon tu risques des surprises (genre, évite 0 pour les strings).

4. Comparaison ancienne vs nouvelle méthode

Tâche LINQ old school Nouveau LINQ .NET 9
Nombre d’étudiants par ville
GroupBy + Select + Count
students.CountBy(s => s.City)
Somme des notes par ville
GroupBy + Select + Sum
students.AggregateBy(..., 0, ...)
Note max par ville
GroupBy + Select + Max
students.AggregateBy(..., ...)
Fréquence des caractères dans une string
GroupBy + Select + Count
word.CountBy(ch => ch)

Utilité concrète pour le taf et les vrais projets

Des méthodes comme CountBy et AggregateBy deviennent incontournables pour faire des stats, préparer des données pour des graphs, faire des tableaux croisés et tout ce genre de trucs. Ça réduit le code, c’est plus lisible et surtout plus fiable : moins de bidouilles à la main pour grouper et agréger, moins de risques de se planter dans la logique.

En entretien pour un poste Junior/Middle, connaître ces nouvelles méthodes LINQ montre que tu suis l’actu de la plateforme, et en prod — ça t’évite de réinventer la roue, tu utilises des trucs propres et faciles à relire et à maintenir.

Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION