CodeGym /Cours /C# SELF /Fusionner des collections avec

Fusionner des collections avec join ( Join)

C# SELF
Niveau 33 , Leçon 0
Disponible

1. Intro

Parfois, on doit bosser avec deux collections différentes qui sont liées par un truc en commun. Genre, t’as une liste de commandes et une autre collection de clients. Comment savoir quelle commande appartient à quel client ? Pour ça, il faut que les deux collections soient reliées par un identifiant commun — genre userId.

Dans les bases de données relationnelles, c’est l’opération JOIN qui fait ça, elle fusionne les lignes de différentes tables par des clés qui matchent. En LINQ, t’as un opérateur pareil — il s’appelle aussi Join.

Imagine deux tables : la première — une liste d’abonnés de la bibliothèque avec leurs identifiants, la deuxième — une liste de commandes de livres, où chaque commande a un id d’abonné. Avec join, on "colle" ces tables par id, et au final on a des paires «abonné + sa commande».

Au fait, si tu pensais que join c’est juste pour les "bases de données", tu rates un truc ! En prog, on fusionne des collections tout le temps, surtout quand tu bosses avec des systèmes externes ou des fichiers structurés (JSON, XML et tous ces tableaux Excel de la compta).

2. Signature de la méthode Join et principe

Voilà à quoi ressemble la méthode Join :


public static IEnumerable<TResult> Join<TOuter, TInner, TKey, TResult>(
    this IEnumerable<TOuter> outer,                 // première collection (externe)
    IEnumerable<TInner> inner,                      // deuxième collection (interne)
    Func<TOuter, TKey> outerKeySelector,            // comment choper la clé de l’élément externe
    Func<TInner, TKey> innerKeySelector,            // comment choper la clé de l’interne
    Func<TOuter, TInner, TResult> resultSelector)   // fonction pour générer le résultat (nouvel élément)

Au début ça fait un peu peur, mais t’inquiète, on va tout décortiquer.
Comment ça marche :
Pour chaque élément de la première collection (outer), LINQ cherche les éléments qui matchent (par la clé) dans la deuxième (inner). Quand les clés sont égales, resultSelector est appelé, et le résultat va dans la collection finale.

3. Exemple : On fusionne clients et leurs commandes

On va créer deux classes et deux collections. C’est la suite logique de notre appli d’apprentissage (genre une petite boutique qu’on code pendant le cours).


public class Customer
{
    public int Id { get; set; }
    public string Name { get; set; } = "";
}

public class Order
{
    public int Id { get; set; }
    public int CustomerId { get; set; }
    public string Product { get; set; } = "";
}

// Collection de clients
var customers = new List<Customer>
{
    new Customer { Id = 1, Name = "Vasya" },
    new Customer { Id = 2, Name = "Petya" },
    new Customer { Id = 3, Name = "Masha" },
};

// Collection de commandes
var orders = new List<Order>
{
    new Order { Id = 101, CustomerId = 2, Product = "Livre" },
    new Order { Id = 102, CustomerId = 1, Product = "Stylo" },
    new Order { Id = 103, CustomerId = 2, Product = "Cahier" },
    new Order { Id = 104, CustomerId = 3, Product = "Gomme" },
};

Maintenant, on veut avoir tous les clients avec leurs commandes. Genre afficher : "Petya a commandé Livre", "Petya a commandé Cahier", etc.

On utilise Join


// On fusionne les clients avec les commandes par customer.Id et order.CustomerId
var query = customers.Join(
    orders,
    customer => customer.Id,          // Comment choper la clé du client
    order => order.CustomerId,        // Comment choper la clé de la commande
    (customer, order) => new          // Quoi faire avec les paires qui matchent (on crée un nouvel objet)
    {
        CustomerName = customer.Name,
        Product = order.Product
    }
);

// On affiche le résultat
foreach (var item in query)
{
    Console.WriteLine($"{item.CustomerName} a commandé {item.Product}");
}

Ce qui va s’afficher :

Vasya a commandé Stylo
Petya a commandé Livre
Petya a commandé Cahier
Masha a commandé Gomme

Fais gaffe : si un client a plusieurs commandes, il sera dans la liste plusieurs fois — une fois par commande. C’est normal !

4. Tableau : Comparaison Join et GroupBy + SelectMany

Opération Résultat Quand l’utiliser
Join
Liste plate de paires Le classique SQL JOIN. Chaque paire (match) = une ligne séparée.
GroupBy + SelectMany
Groupes avec sous-collections Tu veux avoir "client + toutes ses commandes" sous forme "un — à plusieurs".

Les débutants utilisent souvent Join là où il faut une structure «client → liste de commandes». Mais Join marche ligne par ligne et ne groupe pas les données. Pour ça, il y a GroupJoin — on en parle dans la prochaine conf. Ou alors tu utilises GroupBy.

5. Join en Query Syntax (LINQ style SQL)

LINQ supporte deux syntaxes : la chaîne de méthodes (Method Syntax, genre Join(...)) et le style SQL (Query Syntax), qui ressemble visuellement à des requêtes SQL classiques.

Pour certains devs — surtout ceux qui ont déjà fait du SQL — ce style est plus parlant :


var query2 =
    from customer in customers
    join order in orders
        on customer.Id equals order.CustomerId
    select new
    {
        CustomerName = customer.Name,
        Product = order.Product
    };

foreach (var item in query2)
{
    Console.WriteLine($"{item.CustomerName} a commandé {item.Product}");
}

Fais gaffe :
En Query Syntax on utilise le mot-clé equals — l’opérateur == ne marche pas ici !
C’est un piège classique en entretien, surtout pour les débutants 😉

6. Détails importants et pièges

Parfois, il arrive que tous les éléments des collections ne soient pas dans le résultat final. C’est parce que la méthode Join fait ce qu’on appelle un «inner join», donc elle ne fusionne que les éléments dont les clés matchent. Si un client n’a pas de commandes, il ne sera pas dans la liste finale. Pareil, si t’as une commande avec un CustomerId qui n’existe pas chez les clients, cette commande ne sera pas dans le résultat non plus.

Mais si tu veux avoir tous les clients, même ceux sans commandes ? Pour ça, il y a le «left join», qui en LINQ se fait avec GroupJoin et SelectMany. On en parlera dans la prochaine conf. Avec le Join classique, il faut que les deux côtés soient là — sinon pas de match, et l’élément saute du résultat.

7. Fusionner par plusieurs clés (composite key)

Parfois, il faut fusionner des collections non pas par un seul champ, mais plusieurs. Genre : relier des produits et leurs ventes par "Code-produit + Année-vente".

En LINQ, tu fais ça en créant des objets anonymes comme clés :


var sales = ...; // ventes
var products = ...; // produits

var query = products.Join(
    sales,
    prod => new { prod.Code, prod.Year },
    sale => new { sale.ProductCode, sale.Year },
    (prod, sale) => new { prod.Name, sale.Amount }
);

Il faut que les types et les noms des propriétés dans ces objets anonymes soient les mêmes. Sinon, aucun match — même si les valeurs sont pareilles.

8. À quoi ressemble la collection fusionnée — schéma

Voilà un schéma qui montre comment marche join (en version très simplifiée) :


flowchart LR
    subgraph Customers
        A1["Vasya (Id=1)"]
        A2["Petya (Id=2)"]
        A3["Masha (Id=3)"]
    end
    subgraph Orders
        B1["Stylo (CustomerId=1)"]
        B2["Livre (CustomerId=2)"]
        B3["Cahier (CustomerId=2)"]
        B4["Gomme (CustomerId=3)"]
    end

    A1-->|Id=1|B1
    A2-->|Id=2|B2
    A2-->|Id=2|B3
    A3-->|Id=3|B4
Schéma de la fusion clients-commandes par clé

On voit sur le schéma que chaque client est relié à toutes ses commandes — si les clés matchent.

9. Les erreurs et particularités en bref

Une des erreurs les plus courantes — inverser l’ordre des paramètres, surtout si les types de clés sont les mêmes dans les deux collections. Le compilateur ou LINQ ne va pas râler, mais le résultat peut être vide ou bizarre.

Un autre piège classique — essayer de faire un «left join» avec Join, pour garder tous les clients même sans commandes. Mais le Join classique ne prend que les paires qui matchent, il n’inclut pas les éléments sans correspondance.

2
Mission
C# SELF, niveau 33, leçon 0
Bloqué
Fusion simple des listes de clients et de commandes
Fusion simple des listes de clients et de commandes
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION