CodeGym /Cours /C# SELF /Fusion par position avec Z...

Fusion par position avec Zip

C# SELF
Niveau 33 , Leçon 4
Disponible

1. Intro

Imagine deux piles de lettres : la première — avec des enveloppes où il y a des noms, la seconde — avec des cartes postales pour ces destinataires. Ton taf — associer chaque enveloppe avec la carte postale à la même position dans la deuxième pile. La première enveloppe — avec la première carte, la deuxième — avec la deuxième, etc. Tu avances dans les deux piles, tu prends un élément de chaque et tu les "zip" ensemble.

En prog, cette opération s’appelle zip — comme la fermeture éclair qui "colle" deux côtés ensemble, pile par position.

En LINQ, c’est un outil super pratique et puissant pour fusionner des données de deux (parfois plus) séquences, quand l’ordre compte : premier avec premier, deuxième avec deuxième, etc.
À retenir : Zip marche seulement tant qu’il y a des éléments dans les deux collections. Si l’une est plus courte — le résultat sera coupé à la plus courte.

Syntaxe et principe

Zip prend deux (ou plus) listes et les fusionne en une nouvelle : les éléments sont associés par index, donc 0 avec 0, 1 avec 1, etc. Si une des listes se termine avant, les nouvelles paires ne seront plus "zippées" — le résultat aura la taille de la liste la plus courte.

Signature (de base) :


IEnumerable<TResult> Zip<TFirst, TSecond, TResult>(
    this IEnumerable<TFirst> first,
    IEnumerable<TSecond> second,
    Func<TFirst, TSecond, TResult> resultSelector
)

Fais gaffe : Zip ne renvoie pas juste des paires, mais ce que tu mets dans resultSelector. Ça peut être un tuple, une string, un objet, ce que tu veux — tout dépend de ta logique.

  • first et second — les collections à fusionner.
  • resultSelector — une fonction qui prend les éléments courants des deux collections et renvoie le résultat que tu veux.

En mode simple : on avance dans les deux collections en même temps, à chaque étape on fait ce qu’on veut avec la paire.

2. Exemples d’utilisation de Zip — du simple au plus costaud

Exemple le plus simple : additionner deux tableaux de nombres

Imaginons qu’on a deux listes :

  • Notes de maths
  • Notes de littérature
On veut la note totale pour chaque étudiant à la même position.


// Deux tableaux avec les notes des étudiants
int[] mathScores = { 5, 4, 3, 5, 2 };
int[] literatureScores = { 4, 5, 3, 4, 3 };

// On zip par position et on additionne
var totalScores = mathScores.Zip(literatureScores, (math, literature) => math + literature);

foreach (var score in totalScores)
    Console.WriteLine($"Note totale de l’étudiant : {score}");

Note totale de l’étudiant : 9
Note totale de l’étudiant : 9
Note totale de l’étudiant : 6
Note totale de l’étudiant : 9
Note totale de l’étudiant : 5

Tu vois, c’est logique : le premier étudiant a la somme des premières notes, le deuxième — des deuxièmes, etc.

Combiner des strings et des nombres : afficher les produits avec les prix

Disons que t’as une liste de produits et une liste de prix. Tu veux afficher : "NomDuProduit — Prix".


string[] productNames = { "Pomme", "Poire", "Banane" };
decimal[] productPrices = { 50.5m, 60.0m, 35.2m };

var info = productNames.Zip(productPrices, (name, price) => $"{name} — {price} euro");

foreach (var s in info)
    Console.WriteLine(s);

Pomme — 50,5 euro
Poire — 60,0 euro
Banane — 35,2 euro

Utiliser avec des collections d’objets

Imaginons qu’on avait une classe Student et une collection d’étudiants. Et maintenant — un tableau séparé de notes, aligné par ordre :


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

List<Student> students = new List<Student>
{
    new Student { Name = "Vasya" },
    new Student { Name = "Petya" },
    new Student { Name = "Masha" }
};

int[] ratings = { 7, 9, 8 };

var studentsWithRatings = students.Zip(ratings, (student, rating) =>
    $"{student.Name} : note {rating}");

foreach (var s in studentsWithRatings)
    Console.WriteLine(s);

Vasya : note 7
Petya : note 9
Masha : note 8

Fusionner des objets plus complexes

Dans la vraie vie, tu dois souvent fusionner, par exemple, deux listes de commandes de systèmes différents : à chaque commande, associer le résultat du traitement ou l’état.


string[] orders = { "A-1", "B-2", "C-3" };
string[] statuses = { "Terminé", "En cours", "Refusé" };

var orderStatusList = orders.Zip(statuses, (order, status) => new { Order = order, Status = status });

foreach (var os in orderStatusList)
    Console.WriteLine($"Commande {os.Order} : {os.Status}");

Commande A-1 : Terminé
Commande B-2 : En cours
Commande C-3 : Refusé

4. Particularités importantes et erreurs classiques

Quand tu utilises Zip, retiens : la collection finale aura la même taille que la plus courte des entrantes.
Par exemple, si t’as 10 étudiants mais seulement 7 notes, le résultat aura seulement 7 éléments. C’est une cause fréquente de "perte" de données inattendue.

Erreur n°1 : tailles ou ordre des collections pas synchro.
Si tu inverses les listes ou tu oublies de les trier pour que les éléments correspondent, la paire finale sera fausse.
Imagine : la liste des étudiants n’est pas dans le même ordre que celle des notes — Vasya peut choper la note de Petya. C’est comme mettre deux chaussettes différentes : elles sont là, mais ça fait bizarre.

Erreur n°2 : une des collections est vide.
Si au moins une liste est vide, le résultat sera vide.
Zip marche seulement tant qu’il y a des éléments dans les deux séquences. Si une source n’a rien, tu obtiens "rien".

5. Zip avec plusieurs collections

À la base, LINQ ne permettait de fusionner que deux collections. Mais depuis .NET 6, il y a une surcharge qui permet de zipper TROIS (ouais !) collections d’un coup.

Exemple avec trois collections :


string[] names = { "Rey", "Luke", "Leia" };
string[] planets = { "Tatooine", "Tatooine", "Alderaan" };
int[] ages = { 19, 23, 19 };

// En .NET 6+ il y a la surcharge :
var characters = names.Zip(planets, ages, (name, planet, age) =>
    $"{name} ({planet}), {age} ans");

foreach (var c in characters)
    Console.WriteLine(c);

Rey (Tatooine), 19 ans
Luke (Tatooine), 23 ans
Leia (Alderaan), 19 ans

Le nombre d’éléments du résultat — c’est la taille de la plus courte ! Si ages est plus court, le dernier Luke part "sans âge".

6. Zip et LINQ Query Syntax : ça existe ?

T’as peut-être remarqué qu’on utilise toujours la "method syntax". En LINQ Query Syntax, il n’y a pas de mot-clé pour Zip, et tu peux pas le faire avec from ... in .... La raison est simple : le concept de "zip" — c’est une fusion par position, alors que les requêtes LINQ classiques bossent avec join, select, etc., en général pour "lier" par clé, pas par position.

En résumé : Pour Zip on utilise que la syntaxe pointée (enfin, la method syntax quoi) :


var zipped = collection1.Zip(collection2, (a, b) => ...);

Si tu veux absolument utiliser la query syntax — franchement, évite. Mais si t’es vraiment motivé, tu peux te coder ta propre méthode d’extension. 🙂

7. Utiliser Zip dans des applis réelles

Exemple de ta pratique : comparer anciens et nouveaux prix

Imaginons, dans notre appli d’apprentissage, t’as une liste de produits et de temps en temps tu reçois de nouveaux prix. Tu veux afficher comment le prix de chaque produit a changé :


string[] productNames = { "Pomme", "Banane", "Ananas" };
decimal[] oldPrices = { 80.0m, 30.0m, 110.0m };
decimal[] newPrices = { 75.0m, 33.0m, 120.0m };

var priceChanges = productNames
    .Zip(oldPrices, newPrices, (name, oldPrice, newPrice) => 
        $"{name} : avant {oldPrice}, maintenant {newPrice}, changement : {newPrice - oldPrice:+#;-#;0}");

foreach (var s in priceChanges)
    Console.WriteLine(s);

Pomme : avant 80, maintenant 75, changement : -5
Banane : avant 30, maintenant 33, changement : +3
Ananas : avant 110, maintenant 120, changement : +10

Pratique : fusionner des résultats de différentes sources

Dans les projets "en prod", Zip sert souvent à fusionner des résultats de différents API ou tables, où l’ordre des données est garanti (genre, des tableaux de prévisions météo et de mesures réelles).

8. Zip dans les chaînes LINQ : combiner avec d’autres opérateurs

Souvent, Zip est utilisé dans des chaînes LINQ plus longues. Par exemple, tu peux d’abord filtrer les listes, puis les zipper, puis calculer des stats.


var passedMath = mathScores.Where(x => x >= 3);
var passedLit = literatureScores.Where(x => x >= 3);

var passedPairs = passedMath.Zip(passedLit, (m, l) => m + l);
var avgScore = passedPairs.Average();

Console.WriteLine($"Moyenne totale parmi ceux qui ont réussi : {avgScore}");

Astuce : si après Where une des listes est plus courte, Zip coupe le résultat à la plus courte.

Comparer Zip et d’autres méthodes de fusion

Méthode Essence Fusionne par… Résultat : taille…
Zip
Fusionne les éléments par index Index (position) Collection la plus courte
Join
Fusionne par clé Clé commune Toutes les paires qui matchent
GroupJoin
Pour chaque clé, une collection Clé Par la première collection
Concat
Colle les collections à la suite Juste à la fin Somme des tailles

Zip — c’est pour l’alignement positionnel. Join — c’est pour l’alignement par une valeur commune (genre code ou id).

9. Conseils pratiques et erreurs typiques

Quand tu utilises Zip dans ton appli, le plus important — assure-toi que :

  • L’ordre des éléments dans les deux collections est synchro : sinon tu "colles" Vasya avec la note de Petya.
  • Les collections sont bien triées ou préparées pour un parcours synchrone.
  • Le résultat aura toujours la taille de la collection la plus courte.
  • N’utilise pas Zip si tu dois associer les données par une clé ! Pour ça, il y a Join.
  • Autre erreur fréquente — t’as oublié qu’il y a des doublons dans une collection et pas dans l’autre. Ou t’as changé l’ordre pendant un filtrage et perdu la correspondance.
1
Étude/Quiz
Fusion de collections, niveau 33, leçon 4
Indisponible
Fusion de collections
LINQ avancé : fusions et projections
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION