Leçon 11 - LINQ et requêtes

P3 - Manipulation de données

Maîtrisez LINQ (Language Integrated Query) pour manipuler des données efficacement.

Introduction à LINQ

LINQ (Language Integrated Query) est une technologie puissante qui permet d'interroger et de manipuler des collections de données avec une syntaxe élégante et intuitive, similaire à SQL.

Pourquoi utiliser LINQ ?

Opérations de base avec LINQ

Where - Filtrage

Filtre les éléments selon une condition :

C#
using System; using System.Linq; using System.Collections.Generic; List<int> nombres = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; // Syntaxe méthode (recommandée) var pairs = nombres.Where(n => n % 2 == 0); Console.WriteLine("Nombres pairs:"); foreach (var nombre in pairs) { Console.Write($"{nombre} "); // 2 4 6 8 10 } // Syntaxe requête (style SQL) var impairs = from n in nombres where n % 2 != 0 select n; Console.WriteLine("\nNombres impairs:"); foreach (var nombre in impairs) { Console.Write($"{nombre} "); // 1 3 5 7 9 }

Select - Projection

Transforme chaque élément de la collection :

C#
List<int> nombres = new List<int> { 1, 2, 3, 4, 5 }; // Multiplier chaque nombre par 2 var doubles = nombres.Select(n => n * 2); Console.WriteLine(string.Join(", ", doubles)); // 2, 4, 6, 8, 10 // Calculer le carré de chaque nombre var carres = nombres.Select(n => n * n); Console.WriteLine(string.Join(", ", carres)); // 1, 4, 9, 16, 25 // Créer une chaîne formatée var formattes = nombres.Select(n => $"Numéro {n}"); foreach (var texte in formattes) { Console.WriteLine(texte); }

OrderBy / OrderByDescending - Tri

C#
List<string> noms = new List<string> { "Charlie", "Alice", "Bob", "David" }; // Tri croissant var nomsTries = noms.OrderBy(n => n); Console.WriteLine(string.Join(", ", nomsTries)); // Alice, Bob, Charlie, David // Tri décroissant var nomsTriesDesc = noms.OrderByDescending(n => n); Console.WriteLine(string.Join(", ", nomsTriesDesc)); // David, Charlie, Bob, Alice // Tri par longueur var parLongueur = noms.OrderBy(n => n.Length).ThenBy(n => n); Console.WriteLine(string.Join(", ", parLongueur)); // Bob, Alice, David, Charlie

Travail avec des objets complexes

C#
public class Etudiant { public string Nom { get; set; } public int Age { get; set; } public double Moyenne { get; set; } public string Specialite { get; set; } } List<Etudiant> etudiants = new List<Etudiant> { new Etudiant { Nom = "Alice", Age = 20, Moyenne = 15.5, Specialite = "Informatique" }, new Etudiant { Nom = "Bob", Age = 22, Moyenne = 12.0, Specialite = "Mathématiques" }, new Etudiant { Nom = "Charlie", Age = 21, Moyenne = 16.8, Specialite = "Informatique" }, new Etudiant { Nom = "Diana", Age = 19, Moyenne = 14.2, Specialite = "Physique" } }; // Filtrer les étudiants avec une bonne moyenne var bonnesMoyennes = etudiants.Where(e => e.Moyenne >= 14); // Trier par moyenne décroissante var classeParMoyenne = etudiants.OrderByDescending(e => e.Moyenne); // Récupérer uniquement les noms des étudiants en informatique var nomsInfo = etudiants .Where(e => e.Specialite == "Informatique") .Select(e => e.Nom); Console.WriteLine("Étudiants en informatique:"); Console.WriteLine(string.Join(", ", nomsInfo)); // Alice, Charlie

Méthodes d'agrégation

C#
List<int> notes = new List<int> { 12, 15, 18, 10, 16, 14 }; // Count - Compter les éléments int nombreNotes = notes.Count(); Console.WriteLine($"Nombre de notes: {nombreNotes}"); // 6 // Sum - Somme int somme = notes.Sum(); Console.WriteLine($"Somme: {somme}"); // 85 // Average - Moyenne double moyenne = notes.Average(); Console.WriteLine($"Moyenne: {moyenne:F2}"); // 14.17 // Max / Min int maximum = notes.Max(); int minimum = notes.Min(); Console.WriteLine($"Min: {minimum}, Max: {maximum}"); // Min: 10, Max: 18 // Count avec condition int notesReussies = notes.Count(n => n >= 10); Console.WriteLine($"Notes ≥ 10: {notesReussies}"); // 6

Méthodes de recherche

C#
List<string> fruits = new List<string> { "Pomme", "Banane", "Orange", "Kiwi" }; // First - Premier élément (lève une exception si vide) string premierFruit = fruits.First(); Console.WriteLine($"Premier: {premierFruit}"); // Pomme // FirstOrDefault - Premier élément ou valeur par défaut string fruitLong = fruits.FirstOrDefault(f => f.Length > 6); Console.WriteLine($"Fruit > 6 lettres: {fruitLong}"); // Banane // Last - Dernier élément string dernierFruit = fruits.Last(); Console.WriteLine($"Dernier: {dernierFruit}"); // Kiwi // Any - Vérifie si au moins un élément correspond bool contientOrange = fruits.Any(f => f == "Orange"); Console.WriteLine($"Contient Orange: {contientOrange}"); // True // All - Vérifie si tous les éléments correspondent bool tousLongs = fruits.All(f => f.Length > 3); Console.WriteLine($"Tous > 3 lettres: {tousLongs}"); // True // Contains - Vérifie si un élément existe bool contientPomme = fruits.Contains("Pomme"); Console.WriteLine($"Contient Pomme: {contientPomme}"); // True

Opérations avancées

GroupBy - Regroupement

C#
// Regrouper les étudiants par spécialité var parSpecialite = etudiants.GroupBy(e => e.Specialite); foreach (var groupe in parSpecialite) { Console.WriteLine($"\n{groupe.Key}:"); foreach (var etudiant in groupe) { Console.WriteLine($" - {etudiant.Nom} ({etudiant.Moyenne})"); } } // Compter par spécialité var comptesParSpecialite = etudiants .GroupBy(e => e.Specialite) .Select(g => new { Specialite = g.Key, Nombre = g.Count() }); foreach (var item in comptesParSpecialite) { Console.WriteLine($"{item.Specialite}: {item.Nombre} étudiant(s)"); }

Distinct - Éléments uniques

C#
List<int> nombresAvecDoublons = new List<int> { 1, 2, 2, 3, 3, 3, 4, 5, 5 }; var nombresUniques = nombresAvecDoublons.Distinct(); Console.WriteLine(string.Join(", ", nombresUniques)); // 1, 2, 3, 4, 5 // Spécialités uniques var specialitesUniques = etudiants.Select(e => e.Specialite).Distinct(); Console.WriteLine("Spécialités: " + string.Join(", ", specialitesUniques));

Take / Skip - Pagination

C#
List<int> nombres = Enumerable.Range(1, 100).ToList(); // 1 à 100 // Prendre les 10 premiers var dixPremiers = nombres.Take(10); Console.WriteLine("10 premiers: " + string.Join(", ", dixPremiers)); // Sauter les 10 premiers, prendre les 10 suivants var page2 = nombres.Skip(10).Take(10); Console.WriteLine("Page 2: " + string.Join(", ", page2)); // Pagination générique int pageSize = 10; int pageNumber = 3; var page = nombres.Skip((pageNumber - 1) * pageSize).Take(pageSize); Console.WriteLine($"Page {pageNumber}: " + string.Join(", ", page));
Évaluation différée (Lazy Evaluation) :

LINQ utilise l'évaluation différée : les requêtes ne sont exécutées que lorsque vous itérez sur les résultats. Pour forcer l'évaluation immédiate, utilisez :

  • ToList() : Convertit en List<T>
  • ToArray() : Convertit en tableau
  • Count(), Sum(), etc. : Méthodes d'agrégation

Chaînage d'opérations

La vraie puissance de LINQ vient du chaînage d'opérations :

C#
// Exemple complexe : Top 3 des étudiants en informatique var top3Info = etudiants .Where(e => e.Specialite == "Informatique") // Filtrer .OrderByDescending(e => e.Moyenne) // Trier .Take(3) // Limiter .Select(e => new { e.Nom, e.Moyenne }); // Projeter Console.WriteLine("Top 3 en informatique:"); foreach (var etudiant in top3Info) { Console.WriteLine($"{etudiant.Nom}: {etudiant.Moyenne}/20"); } // Statistiques avancées var statistiques = etudiants .Where(e => e.Moyenne >= 10) .GroupBy(e => e.Specialite) .Select(g => new { Specialite = g.Key, NombreEtudiants = g.Count(), MoyenneGenerale = g.Average(e => e.Moyenne), MeilleureMoyenne = g.Max(e => e.Moyenne) }) .OrderByDescending(s => s.MoyenneGenerale); foreach (var stat in statistiques) { Console.WriteLine($"\n{stat.Specialite}:"); Console.WriteLine($" Étudiants: {stat.NombreEtudiants}"); Console.WriteLine($" Moyenne: {stat.MoyenneGenerale:F2}"); Console.WriteLine($" Meilleure note: {stat.MeilleureMoyenne}"); }

Exercice pratique

Exercice :

Créez un système d'analyse de ventes avec LINQ :

  1. Une classe Vente avec produit, montant, date, catégorie
  2. Générez des données de ventes aléatoires
  3. Calculez le total des ventes par catégorie
  4. Trouvez les 5 meilleures ventes
  5. Calculez la moyenne des ventes par mois
  6. Identifiez les produits les plus vendus

Points clés à retenir

Performance :

LINQ est puissant mais peut impacter les performances sur de très grandes collections. Pour des cas critiques, considérez les boucles traditionnelles ou les optimisations spécifiques.