CodeGym /Cours /C# SELF /Aggregation avancée avec A...

Aggregation avancée avec Aggregate

C# SELF
Niveau 32 , Leçon 4
Disponible

1. Intro

Les bons vieux méthodes LINQ — c’est comme la bouffe à la cantine : tu choisis "somme", "minimum" ou "moyenne" et tu passes à la suite. Mais parfois, tu veux un truc spécial. C’est là que Aggregate débarque — genre le chef qui cuisine selon ta recette.

Si tu compares avec la prog fonctionnelle, Aggregate c’est le Reduce (ou fold) : tu parcours la collection et tu la réduis étape par étape en une seule valeur. Comment ? C’est toi qui décides. Contrôle total, créativité totale.

Des trucs cools à faire avec Aggregate :

  • Calculs de sommes chelous : genre produit de tous les nombres, ou somme des pairs/impairs, ou somme selon une règle custom.
  • Concaténer des strings avec ta logique (genre séparateur différent pour les index pairs et impairs).
  • Générer des rapports texte ("listes Markdown", HTML, n’importe quel format custom).
  • Construire des collections avec état modifiable (genre créer un dico à partir d’une liste d’objets selon une règle de clé custom).
  • Tout calcul compliqué qui ne rentre pas dans les fonctions d’agrégation standard.

2. Signature et principe de Aggregate

Jetons un œil à la doc officielle Microsoft sur Enumerable.Aggregate :

public static TAccumulate Aggregate<TSource, TAccumulate>(
    this IEnumerable<TSource> source, 
    TAccumulate seed, 
    Func<TAccumulate, TSource, TAccumulate> func
)

Voilà ce que ça veut dire :

  • source — ta collection de base.
  • seed — "valeur initiale" (pense à un accumulateur de départ).
  • func — une fonction qui prend deux arguments : la valeur accumulée (acc), l’élément courant de la collection, et qui retourne la nouvelle valeur accumulée.

Y’a aussi une version plus simple :

public static TSource Aggregate<TSource>(
    this IEnumerable<TSource> source, 
    Func<TSource, TSource, TSource> func
)

Ici, le "départ" c’est le premier élément de la collection, et ensuite func est appelée du deuxième au dernier.

3. Exemples basiques d’utilisation de Aggregate

On commence avec une mini-devinette pour les étudiants : qui savait que Aggregate peut remplacer Sum ou Product ?

int[] numbers = { 2, 3, 4 };

// Calculer la somme
int sum = numbers.Aggregate((acc, val) => acc + val); // acc = accumulé, val = prochain élément

// Calculer le produit
int product = numbers.Aggregate((acc, val) => acc * val);

Console.WriteLine(sum);     // 9
Console.WriteLine(product); // 24

Ça ressemble à Sum et Multiply, mais c’est toi qui fais ! Petite blague : avec Sum tu fais toujours une somme, mais avec Aggregate — tu fais une somme, une "anti-somme", ou même une "somme des racines carrées".

4. Utiliser Aggregate pour joindre des strings

On va coller toutes les strings ensemble, séparées par une virgule (sans virgule en trop à la fin) :

string[] words = { "C#", "LINQ", "rocks" };
string result = words.Aggregate((acc, word) => acc + ", " + word);
// résultat : "C#, LINQ, rocks"

Si la collection peut être vide, la valeur initiale (seed) est super pratique :

// On commence avec une string vide
string report = words.Aggregate(
    "Technologies : ",
    (acc, word) => acc + word + "; ",
    acc => acc.TrimEnd(' ', ';') // on enlève le "; " de trop à la fin
);

Console.WriteLine(report); // "Technologies : C#; LINQ; rocks"

Checke le troisième argument — la fonction de transformation du résultat (result selector), elle existe dans la version avec seed. C’est comme "le dessert" du plat final.

5. Aggregate dans une appli en dev

Souviens-toi de notre appli d’apprentissage, celle qu’on bidouille depuis quelques jours. Disons qu’on a une classe Student :

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

Liste des étudiants :

var students = new List<Student>
{
    new Student { Name = "Alice", Grade = 5 },
    new Student { Name = "Bob", Grade = 4 },
    new Student { Name = "Dave", Grade = 3 },
    new Student { Name = "Maria", Grade = 5 }
};

Objectif : obtenir une string du genre
"Les meilleurs : Alice, Maria"
— donc tous ceux qui ont Grade == 5.

Comment font les débutants :

var best = "";
foreach (var s in students)
{
    if (s.Grade == 5)
        best += s.Name + ", ";
}
best = best.TrimEnd(',', ' ');
Console.WriteLine("Les meilleurs : " + best);

Et maintenant — version LINQ-style avec Aggregate :

var bestStr = students
    .Where(s => s.Grade == 5)
    .Select(s => s.Name)
    .Aggregate("Les meilleurs : ", (acc, name) => acc + name + ", ")
    .TrimEnd(',', ' ');

Console.WriteLine(bestStr);

Le kiff : minimum de code, lisibilité max. Même si ton boss ne connaît pas LINQ, il pigera ton idée (ou au moins il verra que t’as bossé, même s’il pige pas tout).

6. Scénarios plus avancés

En vrai, l’accumulateur dans Aggregate peut être n’importe quoi : un nombre, une string, un dico, ta propre classe ou struct.

Exemple : compter combien d’étudiants pour chaque note dans la liste :

var gradeCounts = students.Aggregate(
    new Dictionary<int, int>(),
    (dict, student) => {
        if (dict.ContainsKey(student.Grade))
            dict[student.Grade]++;
        else
            dict[student.Grade] = 1;
        return dict;
    }
);

// Pour afficher :
foreach (var pair in gradeCounts)
{
    Console.WriteLine($"Note {pair.Key} : {pair.Value} étudiants");
}

Cette approche, c’est un peu comme faire un GroupBy à la main. Pourquoi pas juste utiliser GroupBy ? Parfois tu veux une agrégation spéciale, pas dispo dans les méthodes LINQ standard, genre additionner seulement si l’étudiant n’est pas Dave, ou générer un rapport pour un rapport.

7. Visualisation : comment marche Aggregate (schéma bloc)

Imaginons un tableau { 2, 4, 3 } et on veut accumuler la somme :


acc : 2 (premier élément)
      |
      v
val : 4
acc = acc + val = 2 + 4 = 6
      |
      v
val : 3
acc = acc + val = 6 + 3 = 9
      |
      v
[Tous les éléments traités]
      |
      v
Résultat : 9

Même schéma pour la version avec seed :


seed : 0
      |
      v
val : 2
acc = 0 + 2 = 2
      |
      v
val : 4
acc = 2 + 4 = 6
      |
      v
val : 3
acc = 6 + 3 = 9
      |
      v
Résultat : 9

Comparaison Aggregate et autres méthodes d’agrégation

Méthode Comportement standard Flexibilité Pour collections vides Exemple
Sum
Fait la somme des nombres Basse Retourne 0
[1,2,3].Sum() = 6
Count
Compte les éléments Basse Retourne 0
[a,b].Count() = 2
Aggregate
Calcul custom Haute Besoin d’un seed
[1,2,3].Aggregate((a,b)=>a*b)=6
string.Join
Colle les strings Moyenne Pour vide = ""
string.Join(", ", arr)

8. Conseils pratiques, erreurs classiques et points importants

Vu que Aggregate est super flexible, tu peux avoir des surprises si tu l’utilises mal. Les erreurs les plus courantes :

Parfois les devs oublient le seed (valeur initiale) et ne pensent pas que si la collection est vide, la version sans seed va balancer une exception (InvalidOperationException). Donc pour les collections vides, utilise la version avec seed :

var sum = new int[0].Aggregate(0, (acc, n) => acc + n); // Ça marche ! Retourne 0

Si tu accumules une string avec Aggregate, tu risques d’avoir un séparateur en trop (genre une "," à la fin). Le mieux c’est de l’enlever avec .TrimEnd(',', ' ') — ou utilise string.Join si tu veux juste coller des strings.

Un accumulateur de type modifiable (genre List ou Dictionary) est souvent utilisé dans Aggregate, mais fais gaffe : si tu le modifies sur place (in-place), à chaque étape toutes les références pointent sur le même objet. Ça peut donner des effets bizarres en cas d’opérations parallèles ou si tu t’attends à une copie. Donc en style fonctionnel pur, à chaque étape retourne un nouvel objet, pas modifie l’ancien.

Dans du code partagé, évite de rendre Aggregate trop compliqué juste pour frimer : pour les débutants, c’est plus chaud que les foreach ou les agrégats standards. Si la tâche est simple — utilise Sum, Count, Join. Mais si tu dois "fabriquer du texte selon un modèle chelou" — Aggregate est ton pote !

9. Lien avec le taf, les entretiens et les frameworks

Dans l’industrie, la méthode Aggregate apparaît souvent là où il faut des calculs ou des réductions de données pas banales, genre pour générer des rapports complexes, des stats, des graphes, calculer des hash, générer des id uniques ou même construire des composants UI à partir de collections selon une logique custom.

En entretien, les questions sur LINQ tombent quasi tout le temps : "Comment obtenir la somme des éléments d’un tableau ?", "Comment transformer une liste de strings en une seule string ?" ou "Comment compter le nombre d’éléments uniques ?" — et souvent on attend des solutions avec LINQ et aussi Aggregate. Parfois c’est créatif : "Peux-tu avec LINQ calculer la somme des carrés des nombres pairs, puis retourner une string qui décrit ce process ?"

Dans plein de libs et frameworks .NET connus, genre Entity Framework, Dapper, RavenDB, la méthode Aggregate est rarement utilisée direct côté base de données, mais côté code elle sert à fond pour agréger en mémoire.

2
Mission
C# SELF, niveau 32, leçon 4
Bloqué
Agrégation la plus simple — produit d’un tableau
Agrégation la plus simple — produit d’un tableau
1
Étude/Quiz
Groupement des données, niveau 32, leçon 4
Indisponible
Groupement des données
LINQ avancé : groupement et fonctions d'agrégation
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION