1. Introduction
Travailler avec des collections, ce n’est pas juste les parcourir, filtrer ou trier. Très souvent, tu dois modifier ou retravailler ces collections pour qu’elles collent à tes besoins : par exemple, prendre une collection de chaînes et la transformer en collection de nombres, virer les doublons d’une liste ou carrément changer la structure des données.
Tout ça, tu peux le faire avec les méthodes standard des collections, des boucles simples et des algos de base. C’est un peu plus long qu’avec LINQ, mais au moins c’est super clair et ça t’aide à piger comment marchent les collections.
Les façons principales de modifier des collections
Tu peux modifier les collections de plein de façons, mais en général tu as besoin d’une de ces approches :
- Modification du contenu : ajouter, supprimer ou remplacer des éléments.
- Transformation des éléments : prendre la collection d’origine et en faire une nouvelle — d’une autre structure, type ou forme (genre, passer de List<int> à List<string>).
- Changer la vue : restructurer la collection — par exemple, trier, inverser (reverse) ou grouper.
On va surtout se concentrer sur les deux premiers groupes, parce que le tri a déjà été vu dans une autre conf.
Collections mutables et immuables : un point important
Faut pas oublier que certaines collections en .NET peuvent être modifiées sans souci (genre List<T>), et d’autres — non (IReadOnlyList<T>, tableaux avec modifieurs en lecture seule, etc.).
- Modification — on change la collection en question (genre avec Add, Remove, Clear, etc.).
- Transformation — on touche pas à l’original, on crée une nouvelle collection, souvent en créant une nouvelle liste et en la remplissant à partir de la collection d’origine.
2. Modification du contenu des collections
Toutes les collections qui implémentent ICollection<T> proposent des méthodes de base pour modifier le contenu. On va voir ça avec un exemple de catalogue de livres.
Ajouter et supprimer des éléments
public class Book
{
public string Titre { get; set; }
public string Auteur { get; set; }
public int Annee { get; set; }
}
List<Book> livres = new List<Book>
{
new Book { Titre = "Code propre", Auteur = "Robert Martin", Annee = 2008 },
new Book { Titre = "CLR via C#", Auteur = "Jeffrey Richter", Annee = 2012 }
};
// Ajouter un nouveau livre
livres.Add(new Book { Titre = "Head First C#", Auteur = "Andrew Stellman", Annee = 2010 });
// Supprimer un livre selon une condition (par exemple, par auteur)
for (int i = livres.Count - 1; i >= 0; i--)
{
if (livres[i].Auteur == "Robert Martin")
livres.RemoveAt(i);
}
// Supprimer un objet précis (s’il est dans la liste)
Book unLivre = livres[0];
livres.Remove(unLivre);
// Vider toute la collection
livres.Clear();
// Insérer un élément à une position précise
livres.Insert(0, new Book { Titre = "Pro C# 9", Auteur = "Andrew Troelsen", Annee = 2021 });
Remplacer et mettre à jour des éléments
Imaginons qu’on s’est planté sur l’année de sortie. Comment corriger ?
// On trouve le bon livre avec une boucle et on corrige l’année
for (int i = 0; i < livres.Count; i++)
{
if (livres[i].Titre == "Head First C#")
{
livres[i].Annee = 2018; // Année corrigée
break;
}
}
3. Transformation des collections
Transformation du type d’éléments (par exemple, de Book à string)
Obtenir la liste des titres de tous les livres :
List<string> titresLivres = new List<string>();
foreach (Book livre in livres)
{
titresLivres.Add(livre.Titre);
}
foreach (var titre in titresLivres)
{
Console.WriteLine(titre);
}
Obtenir les années de tous les livres :
List<int> anneesLivres = new List<int>();
foreach (Book livre in livres)
{
anneesLivres.Add(livre.Annee);
}
Transformation en un nouveau type/structure :
public class InfoLivreResume
{
public string Titre;
public int Annee;
}
List<InfoLivreResume> infosResumes = new List<InfoLivreResume>();
foreach (Book livre in livres)
{
infosResumes.Add(new InfoLivreResume { Titre = livre.Titre, Annee = livre.Annee });
}
foreach (var info in infosResumes)
{
Console.WriteLine($"{info.Titre} ({info.Annee})");
}
Transformer une collection de collections en une seule (flat map)
Si un livre a une liste de tags, obtenir une seule liste de tous les tags :
public class Book
{
public string Titre { get; set; }
public List<string> Tags { get; set; }
}
List<Book> livresAvecTags = new List<Book>
{
new Book { Titre = "Code propre", Tags = new List<string> { "Clean Code", "Refactoring" } },
new Book { Titre = "CLR via C#", Tags = new List<string> { "CLR", "Internals" } }
};
List<string> tousLesTags = new List<string>();
foreach (var livre in livresAvecTags)
{
foreach (var tag in livre.Tags)
{
tousLesTags.Add(tag);
}
}
foreach (string tag in tousLesTags)
{
Console.WriteLine(tag);
}
4. Méthodes de transformation de collections souvent utilisées
ToArray
Pour obtenir un tableau à partir d’une liste :
string[] tableauTitresLivres = titresLivres.ToArray();
Distinct — virer les doublons
Auteurs uniques (sans LINQ) :
List<string> auteurs = new List<string>();
foreach (Book livre in livres)
{
if (!auteurs.Contains(livre.Auteur))
auteurs.Add(livre.Auteur);
}
Reverse — inverser une collection
Pour changer l’ordre en inverse :
livres.Reverse(); // modifie sur place !
Si tu veux pas toucher à l’original :
var inverses = new List<Book>(livres);
inverses.Reverse();
Tri (voir la conf sur le tri)
livres.Sort((a, b) => a.Annee.CompareTo(b.Annee)); // tri par année
Groupement par champ (émulation de GroupBy)
Grouper les livres par auteur (obtenir un dico "auteur — liste de livres") :
Dictionary<string, List<Book>> livresParAuteur = new Dictionary<string, List<Book>>();
foreach (Book livre in livres)
{
if (!livresParAuteur.ContainsKey(livre.Auteur))
livresParAuteur[livre.Auteur] = new List<Book>();
livresParAuteur[livre.Auteur].Add(livre);
}
foreach (var pair in livresParAuteur)
{
Console.WriteLine($"Auteur : {pair.Key}");
foreach (var l in pair.Value)
Console.WriteLine($" {l.Titre}");
}
5. Astuces utiles
- Les opérations de transformation avec des boucles marchent partout, tout le temps.
- Pour virer les doublons, utilise des collections temporaires et les méthodes Contains/Add.
- Ne modifie pas une collection pendant que tu la parcours avec foreach ! Si tu dois supprimer plein d’éléments, commence par les mettre dans une autre liste.
6. Exemples de tâches typiques
Obtenir la liste des livres d’une certaine année
List<Book> livresRecents = new List<Book>();
foreach (Book livre in livres)
{
if (livre.Annee > 2010)
livresRecents.Add(livre);
}
foreach (var livre in livresRecents)
{
Console.WriteLine($"{livre.Titre} ({livre.Annee})");
}
Afficher toutes les années de publication uniques par ordre croissant
List<int> annees = new List<int>();
foreach (Book livre in livres)
{
if (!annees.Contains(livre.Annee))
annees.Add(livre.Annee);
}
annees.Sort();
foreach (int annee in annees)
Console.WriteLine(annee);
Préparer les livres pour l’export (créer une liste-DTO)
public class ExportLivre
{
public string Nom;
public string Auteur;
public int AnneePublication;
}
List<ExportLivre> livresPourExport = new List<ExportLivre>();
foreach (Book livre in livres)
{
livresPourExport.Add(new ExportLivre
{
Nom = livre.Titre,
Auteur = livre.Auteur,
AnneePublication = livre.Annee
});
}
7. Erreurs typiques et pièges
Les méthodes comme Add, Remove, Clear, Insert et Sort modifient la collection sur place.
Si tu veux une nouvelle collection — crée une nouvelle liste et ajoute-y ce qu’il te faut.
Quand tu supprimes des éléments pendant que tu parcours une collection, fais-le à l’envers (for (int i = Count-1; i >= 0; i--)).
Si tu veux une liste avec des éléments uniques, fais gaffe aux doublons : utilise Contains ou HashSet<T>.
GO TO FULL VERSION