Regroupement par plusieurs colonnes dans LINQ : exemples et bonnes pratiques

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Comment regrouper des données par deux champs ou plus avec LINQ en C# ?

\n\n

Bonjour, ami ! Si tu as déjà écrit des requêtes vers des bases de données en SQL, tu te souviens sûrement de la construction GROUP BY avec plusieurs colonnes. Elle permet de diviser les données en groupes logiques — par exemple, regrouper les ventes d'abord par ville, puis à l'intérieur par catégorie de produit. En C#, on utilise GroupBy de LINQ dans le même but. Mais voilà le problème : le GroupBy standard n'accepte qu'une seule clé. Comment faire si l'on doit regrouper par plusieurs colonnes ?

\n\n

Ne t'inquiète pas ! La solution est élégante et simple — nous créons un type anonyme qui combine les champs nécessaires en une seule clé composite. Dans cet article, je vais te montrer non seulement la syntaxe de base, mais aussi des exemples réels avec du code que tu pourras appliquer immédiatement dans tes projets. C'est parti !

\n\n

Problème : une seule clé, c'est trop peu

\n\n

Imagine que tu as une liste d'étudiants :

\n\n
public class Student\n{\n    public string Name { get; set; }\n    public string Course { get; set; }\n    public int Grade { get; set; }\n}\n\nList<Student> students = new List<Student>\n{\n    new Student { Name = "Anna", Course = "Mathématiques", Grade = 85 },\n    new Student { Name = "Boris", Course = "Mathématiques", Grade = 90 },\n    new Student { Name = "Anna", Course = "Physique", Grade = 78 },\n    new Student { Name = "Boris", Course = "Physique", Grade = 82 },\n    new Student { Name = "Anna", Course = "Mathématiques", Grade = 95 }\n};
\n\n

Tu veux connaître la note moyenne de chaque étudiant pour chaque cours. Si tu utilises GroupBy uniquement par nom, les données d'Anna en mathématiques et en physique seront mélangées. Si tu regroupes uniquement par cours, le lien avec l'étudiant est perdu. Il te faut un regroupement par deux colonnes : Name + Course.

\n\n

Solution : le type anonyme comme clé composite

\n\n

En C#, nous pouvons créer un objet temporaire avec les champs nécessaires directement sur place :

\n\n
var grouped = students\n    .GroupBy(s => new { s.Name, s.Course })\n    .Select(g => new\n    {\n        g.Key.Name,\n        g.Key.Course,\n        AverageGrade = g.Average(st => st.Grade)\n    });\n\nforeach (var item in grouped)\n{\n    Console.WriteLine($"{item.Name} | {item.Course} | Moyenne : {item.AverageGrade:F2}");\n}
\n\n

Résultat :
\nAnna | Mathématiques | Moyenne : 90.00
\nBoris | Mathématiques | Moyenne : 90.00
\nAnna | Physique | Moyenne : 78.00
\nBoris | Physique | Moyenne : 82.00

\n\n

Remarque : new { s.Name, s.Course } est le type anonyme. LINQ compare automatiquement les objets sur toutes leurs propriétés (égalité de valeur).

\n\n

Travailler avec IGrouping et les collections imbriquées

\n\n

Parfois, il ne s'agit pas d'agréger les données, mais de conserver tous les éléments d'origine à l'intérieur du groupe. Pour cela, on utilise l'interface IGrouping<TKey, TElement>. Chaque groupe contient une clé et une collection d'éléments :

\n\n
var groups = students.GroupBy(s => new { s.Name, s.Course });\n\nforeach (var group in groups)\n{\n    Console.WriteLine($"Étudiant : {group.Key.Name}, Cours : {group.Key.Course}");\n    foreach (var student in group)\n    {\n        Console.WriteLine($"  Note : {student.Grade}");\n    }\n}
\n\n

Cette approche est idéale lorsque tu as besoin, par exemple, de générer un rapport détaillé.

\n\n

Syntaxe query vs fluent — que choisir ?

\n\n

LINQ prend en charge deux styles d'écriture de requêtes. Voyons les deux :

\n\n

1. Fluent (syntaxe de méthode)

\n
var result = students\n    .GroupBy(s => new { s.Name, s.Course })\n    .Select(g => new { g.Key.Name, g.Key.Course, Count = g.Count() });
\n\n

2. Query (syntaxe d'expressions de type SQL)

\n
var result = from student in students\n             group student by new { student.Name, stud                

Blogs

Book Recommendations