1. Intro
Soyons honnêtes, les tableaux c'est cool, mais ça a ses limites. Tu veux changer la taille ? Faut créer un nouveau tableau et copier les éléments à la main ! Tu veux chercher vite fait un élément par clé ? Le tableau va te dire : "Bah, débrouille-toi tout seul".
Dans la vraie vie, y'a plein de scénarios où les tableaux sont relous. Imagine que tu codes une appli pour gérer les livres d'une bibliothèque (coucou, notre mini-système d'apprentissage !). Au début t'as 5 livres — le tableau suffit. Une semaine après, t'en as déjà 500, et puis un mois plus tard, y'en a qui reviennent, d'autres qui se perdent... C'est là que les collections débarquent !
Les collections, c'est des conteneurs qui savent :
- Changer de taille tout seuls.
- Permettre une recherche, un ajout, une suppression rapide.
- Donner des moyens plus pratiques de bosser avec les données : tri, filtrage, traitement en groupe.
En .NET, t'as plusieurs "familles" de collections. Aujourd'hui, on va voir les principales : listes (List<T>), dictionnaires (Dictionary<TKey, TValue>), ensembles (HashSet<T>), files d'attente, piles, et aussi les interfaces qui sont à la base de tout ça.
2. Les grands types de collections
Même si on n'a pas encore plongé dans les types génériques de collections, c'est important de piger quelles sont les catégories principales de collections et à quoi elles servent. Imagine ça comme différents types de "boîtes", chacune avec ses particularités :
Listes (Lists)
C'est quoi ? Une séquence ordonnée d'éléments. Comme une liste de courses ou la liste des élèves dans un carnet.
Points clés : Les éléments ont un ordre (tu peux les choper par index, comme dans un tableau). Ils peuvent être en double. Taille dynamique.
Quand l'utiliser ? Quand l'ordre des éléments compte, et que tu veux pouvoir ajouter/enlever vite fait des éléments à la fin, ou accéder à un élément par sa position.
Exemple IRL : File à la caisse, liste des participants à un webinaire, séquence d'images dans une animation.
Dictionnaires/Maps (Dictionaries/Maps)
C'est quoi ? Un ensemble de paires "clé-valeur". Comme un vrai dico, où chaque mot (clé) a sa définition (valeur).
Points clés : Chaque clé est unique. La clé sert à retrouver vite la valeur associée. L'ordre des éléments n'est pas garanti.
Quand l'utiliser ? Quand tu dois retrouver vite une valeur à partir d'un identifiant unique (clé).
Exemple IRL : Carnet d'adresses (nom - téléphone), base de données produits (ID produit - description), paramètres d'appli (nom du paramètre - valeur).
Ensembles (Sets)
C'est quoi ? Un ensemble non ordonné d'éléments uniques. Comme un ensemble en maths.
Points clés : Pas de doublons. L'ordre n'est pas garanti. Optimisé pour vérifier si un élément est là et faire des opérations d'ensemble (union, intersection).
Quand l'utiliser ? Quand tu veux stocker des valeurs uniques et vérifier vite si un élément est dans le lot.
Exemple IRL : Liste des visiteurs uniques d'un site, ensemble de tags pour un article, liste de mots pour l'autocomplétion (sans doublons).
Files d'attente (Queues)
C'est quoi ? Une collection qui marche en mode "premier arrivé — premier sorti" (FIFO - First-In, First-Out).
Points clés : Les éléments s'ajoutent à la fin et se retirent au début.
Quand l'utiliser ? Pour modéliser des process où l'ordre de traitement est important, genre système de tickets support, file d'impression.
Piles (Stacks)
C'est quoi ? Une collection qui marche en mode "dernier arrivé — premier sorti" (LIFO - Last-In, First-Out).
Points clés : Les éléments s'ajoutent et se retirent du même côté (le haut de la pile).
Quand l'utiliser ? Pour suivre l'historique des actions (annuler dans un éditeur), gérer des structures imbriquées, la récursivité.
Différences entre les types de collections
| Type de collection | Analogie | Principe de base | Accès par index ? | Ordre des éléments ? | Doublons autorisés ? | Opérations principales |
|---|---|---|---|---|---|---|
| Tableau | Rangée de cases numérotées | Taille fixe | Oui | Oui | Oui | Accès/modif par index |
| Liste | Liste de courses | Dynamique, ordonné | Oui | Oui | Oui | Ajout, suppression, recherche |
| Dictionnaire | Dico (clé-valeur) | Clés uniques | Non | Non (en général) | Non (par clé) | Accès par clé, ajout |
| Ensemble | Lot d'objets uniques | Uniquement des éléments uniques | Non | Non | Non | Vérif présence, union |
| File d'attente | File à la caisse | FIFO (Premier arrivé - premier sorti) | Non | Oui | Oui | Ajout à la fin, retrait au début |
| Pile | Pile d'assiettes | LIFO (Dernier arrivé - premier sorti) | Non | Oui | Oui | Ajout en haut, retrait en haut |
3. Liste : List<T>
La liste, c'est la collection la plus utilisée en C#. Même plus que le tableau. Une liste, c'est comme un tableau, mais elle grandit toute seule. Tu peux ajouter et enlever des éléments sans te prendre la tête.
using System;
using System.Collections.Generic;
var numbers = new List<int>(); // On crée une liste vide d'entiers
numbers.Add(10); // On ajoute un élément
numbers.Add(15);
numbers.Add(42);
Console.WriteLine(numbers[0]); // 10
numbers.Remove(15); // On enlève un élément par valeur
foreach (var number in numbers)
{
Console.WriteLine(number);
}
// Affichera : 10 et 42
Pourquoi List<T> est mieux qu'un tableau pour une collection dont tu connais pas la taille à l'avance ?
— Parce que t'as pas à gérer la mémoire ou copier le tableau à la main quand tu ajoutes des éléments — la collection s'en occupe !
Quand utiliser List<T> ?
- Liste dynamique, quand tu veux ajouter, enlever, modifier des éléments.
- Pas besoin de recherche rapide par clé (ça c'est pour les dictionnaires).
- Super pratique pour bosser avec des ensembles ordonnés.
4. Dictionnaire Dictionary<TKey, TValue>
Un tableau (et une liste) te permet de stocker une liste de valeurs dans des cases, chaque case ayant un index. Mais un dictionnaire, c'est une collection où tu peux utiliser une chaîne (un nom) à la place d'un nombre (index). Ce nom de case, c'est la clé.
Si tu veux retrouver vite une valeur à partir d'une clé (genre numéro de carte lecteur — nom du lecteur), il te faut un dictionnaire.
using System.Collections.Generic;
var phoneBook = new Dictionary<string, string>();
phoneBook["Anya"] = "+79992221133";
phoneBook["Maxime"] = "+79998887766";
Console.WriteLine(phoneBook["Anya"]); // +79992221133
// Tu peux vérifier si la clé existe :
if (phoneBook.ContainsKey("Vasya"))
{
Console.WriteLine(phoneBook["Vasya"]);
}
else
{
Console.WriteLine("Pas de numéro comme ça !");
}
Fun fact : Les dictionnaires sont souvent appelés "tableaux associatifs". Ils sont basés sur une table de hachage, ce qui permet de chercher par clé super vite (quasi instantané, sauf collisions — mais on verra ça plus tard).
Points clés
- La clé est unique : pas deux clés identiques dans un dico.
- Les valeurs peuvent être en double.
- Recherche, ajout, suppression ultra rapides par clé.
5. Ensemble : HashSet<T>
En plus des listes et des dicos, les ensembles sont aussi super utilisés. C'est presque comme une liste, mais plus simple : une liste sans ordre fixe. Un ensemble stocke juste un lot de valeurs, pour les cas où l'ordre on s'en fiche.
Par exemple, tu veux juste savoir si un truc est dans le lot, sans doublons, et l'ordre t'importe peu — alors tu prends un ensemble.
using System.Collections.Generic;
var knownUsers = new HashSet<string>();
knownUsers.Add("admin");
knownUsers.Add("guest");
knownUsers.Add("admin"); // Ajout en double — ignoré
Console.WriteLine(knownUsers.Contains("admin")); // True
Console.WriteLine(knownUsers.Count); // 2
Un ensemble vérifie super vite si un élément est là.
Pourquoi utiliser des ensembles ?
— Si tu veux stocker tous les utilisateurs uniques qui ont ouvert l'appli ce mois-ci, ou genre la liste des auteurs uniques de livres.
Particularités
- Stocke que des éléments uniques (ajout d'un doublon = ignoré).
- Pas d'index comme dans une liste.
- Vérif de présence rapide.
6. Files d'attente et piles
Y'a aussi des structures pour des cas spéciaux : file d'attente et pile. En vrai, c'est comme une liste, mais avec des règles pour ajouter et retirer les éléments.
Queue<T> : file d'attente (first in — first out)
Parfois tu dois gérer une "queue" — un nouvel élément va à la fin, et tu les retires au début.
using System.Collections.Generic;
var queue = new Queue<string>();
queue.Enqueue("Premier");
queue.Enqueue("Deuxième");
queue.Enqueue("Troisième");
Console.WriteLine(queue.Dequeue()); // "Premier"
Console.WriteLine(queue.Peek()); // "Deuxième", mais ne l'enlève pas
Stack<T> : pile (first in — last out)
La pile, c'est l'inverse : le dernier arrivé sort en premier. On l'utilise dans les parseurs, la gestion des appels de fonctions, ou même pour annuler des actions dans les éditeurs.
using System.Collections.Generic;
var stack = new Stack<string>();
stack.Push("Un");
stack.Push("Deux");
stack.Push("Trois");
Console.WriteLine(stack.Pop()); // "Trois"
Console.WriteLine(stack.Peek()); // "Deux"
7. Tableau : comparaison des principales collections
| Collection | Éléments uniques | Accès par index | Recherche rapide par clé | Opérations d'insertion/suppression |
|---|---|---|---|---|
|
Non | Oui | Non | Rapide à la fin |
|
Clés | Non | Oui | Rapide par clé |
|
Oui | Non | Oui* | Rapide par valeur |
|
Non | Non | Non | Rapide (FIFO) |
|
Non | Non | Non | Rapide (LIFO) |
On va détailler chaque collection dans les prochaines confs. Et on va commencer par la mystérieuse lettre <T>...
GO TO FULL VERSION