📌 Questions / Réponses sur List<T> en C#
1. Quelle est la différence entre List<T> et un tableau (T[]) ?
-
Réponse :
-
Un tableau a une taille fixe,
List<T>est dynamique (elle grossit automatiquement si nécessaire). -
List<T>offre des méthodes pratiques (Add,Remove,Find, etc.) que les tableaux n’ont pas. -
En mémoire, un tableau est contigu, tandis que
List<T>encapsule un tableau interne redimensionné.
-
2. Quelle est la complexité des opérations courantes sur List<T> ?
-
Réponse :
-
Add: O(1) amorti (mais peut être O(n) si redimensionnement). -
InsertetRemove: O(n) (car décalage des éléments). -
Contains/IndexOf: O(n). -
Accès par index (
list[i]) : O(1).
-
3. Comment fonctionne la capacité (Capacity) et la taille (Count) d’une List<T> ?
-
Réponse :
-
Count= nombre d’éléments réels stockés. -
Capacity= taille du tableau interne alloué. -
Quand
CountdépasseCapacity, laListalloue un tableau plus grand (souvent le double) et copie les éléments.
-
4. Quelle est la différence entre List<T> et IEnumerable<T> / ICollection<T> / IList<T> ?
-
Réponse :
-
IEnumerable<T>: permet uniquement l’itération (foreach). -
ICollection<T>: ajoute des méthodes commeAdd,Remove,Count. -
IList<T>: ajoute l’accès par index etInsert,RemoveAt. -
List<T>implémente tout ça (héritage des trois).
-
5. Que se passe-t-il si on ajoute un élément dans une List<T> pendant un foreach ?
-
Réponse :
-
Une exception
InvalidOperationExceptionest levée, car la collection est modifiée pendant l’énumération.
-
6. Quelle est la différence entre Clear() et RemoveAll() ?
-
Réponse :
-
Clear(): supprime tous les éléments, Count devient 0. -
RemoveAll(predicate): supprime uniquement les éléments qui satisfont la condition.
-
7. Comment supprimer efficacement les doublons d’une List<T> ?
-
Réponse :
-
Utiliser LINQ :
list = list.Distinct().ToList(); -
Ou utiliser un
HashSet<T>pour filtrer.
-
8. Quelle est la différence entre List<T> et LinkedList<T> ?
-
Réponse :
-
List<T>: basé sur un tableau, accès indexé rapide O(1), insertions/suppressions coûteuses O(n). -
LinkedList<T>: basé sur des nœuds, insertions/suppressions rapides O(1) si on a la référence du nœud, mais accès par index est O(n).
-
9. Peut-on rendre une List<T> en lecture seule ?
-
Réponse :
-
Oui, avec
list.AsReadOnly(). -
Ou utiliser
IReadOnlyList<T>.
-
10. Quelle est la différence entre List<T>.ForEach() et foreach ?
-
Réponse :
-
ForEach(Action<T>)exécute une action sur chaque élément mais n’autorise pasbreak/continue. -
foreachest plus flexible et lisible.
-
🔥 Questions avancées et pièges sur List<T> en C#
1. Que se passe-t-il si on stocke des struct dans une List<T> ?
-
Réponse :
-
Chaque élément est copié (valeur) lors de l’ajout.
-
Quand on accède à un élément (
list[i]), on obtient une copie : modifier ses champs n’affecte pas l’élément dans la liste. -
Exemple piège :
struct Point { public int X; public int Y; } var list = new List<Point> { new Point { X = 1, Y = 2 } }; list[0].X = 99; // ne modifie pas l’élément dans la liste !
-
2. Pourquoi List<object> peut entraîner du boxing quand on stocke des valeurs ?
-
Réponse :
-
Si on met un type valeur (
int,double,struct…) dans uneList<object>, il est boxé (copié dans le heap). -
Cela dégrade la performance et augmente la mémoire utilisée.
-
Solution : utiliser
List<T>avec unTfortement typé.
-
3. Quelle est la différence entre Capacity et TrimExcess() ?
-
Réponse :
-
Capacitypeut être supérieur àCount. -
TrimExcess()réduitCapacitypour coller auCountréel (libère la mémoire). -
⚠️ Attention :
TrimExcess()peut être coûteux si appelé fréquemment dans des boucles.
-
4. Que se passe-t-il si on appelle list.AddRange(list) ?
-
Réponse :
-
On ajoute la liste à elle-même.
-
Résultat : duplication des éléments (aucune exception).
-
Exemple :
[1,2,3]devient[1,2,3,1,2,3].
-
5. Quelle est la différence entre List<T> et ArrayList ?
-
Réponse :
-
ArrayListstocke desobject, donc nécessite du boxing/unboxing pour les types valeurs. -
List<T>est générique et évite ce problème. -
List<T>est plus performant et typesafe (pas de cast à faire).
-
6. Quelle est la complexité réelle quand la List<T> double sa capacité ?
-
Réponse :
-
Le
Addest O(1) amorti. -
Mais quand le tableau interne doit s’agrandir : allocation + copie → O(n).
-
Donc, dans le pire cas,
Addest O(n).
-
7. Peut-on modifier une List<T> en parallèle (multithreading) ?
-
Réponse :
-
Non,
List<T>n’est pas thread-safe. -
Plusieurs
Add/Removeconcurrents → comportement indéfini. -
Pour la synchronisation : utiliser
lock, ouConcurrentBag<T>,ConcurrentQueue<T>…
-
8. Quelle est la différence entre Find() et Where() (LINQ) ?
-
Réponse :
-
Find()renvoie le premier élément correspondant oudefault(T). -
Where()renvoie un IEnumerable` avec tous les éléments correspondants. -
FindAll()est l’équivalent proche deWhere().ToList().
-
9. Pourquoi une List<T> peut-elle "fuir" de la mémoire même après Clear() ?
-
Réponse :
-
Clear()metCount = 0, mais les références dans le tableau interne existent toujours (elles sont juste ignorées). -
Pour vraiment libérer :
list = new List<T>()ouTrimExcess()aprèsClear().
-
10. Que se passe-t-il si on parcourt une List<T> avec un for et qu’on supprime des éléments ?
-
Réponse :
-
Si on fait
list.RemoveAt(i)pendant unfor, les indices changent et on risque de sauter des éléments. -
Solution : parcourir à l’envers (
for (int i = list.Count-1; i >= 0; i--)).
-
🔹 Algorithmes fréquents avec List<T> en C#
1. Parcourir une liste et afficher les éléments
var list = new List<int> { 1, 2, 3, 4, 5 };
foreach (var n in list)
Console.WriteLine(n);
2. Trouver le minimum et le maximum
var list = new List<int> { 10, 5, 8, 20, 3 };
int min = list.Min(); // 3
int max = list.Max(); // 20
⚠️ En entretien on peut te demander de coder toi-même :
int min = list[0];
foreach (var n in list)
if (n < min) min = n;
3. Recherche linéaire dans une liste
var list = new List<string> { "Alice", "Bob", "Charlie" };
string target = "Bob";
bool found = list.Contains(target); // True
Sans Contains() (implémentation manuelle) :
bool found = false;
foreach (var name in list)
if (name == target) { found = true; break; }
4. Supprimer les doublons
var list = new List<int> { 1, 2, 2, 3, 4, 4, 5 };
var noDuplicates = list.Distinct().ToList(); // [1,2,3,4,5]
Implémentation sans LINQ :
var unique = new List<int>();
foreach (var n in list)
if (!unique.Contains(n))
unique.Add(n);
5. Inverser une liste
var list = new List<int> { 1, 2, 3, 4, 5 };
list.Reverse(); // [5,4,3,2,1]
Implémentation manuelle (swap) :
for (int i = 0; i < list.Count / 2; i++)
{
int temp = list[i];
list[i] = list[list.Count - 1 - i];
list[list.Count - 1 - i] = temp;
}
6. Tri d’une liste
var list = new List<int> { 5, 3, 8, 1, 4 };
list.Sort(); // [1,3,4,5,8]
Tri décroissant :
list.Sort((a, b) => b.CompareTo(a));
7. Recherche binaire (si la liste est triée)
var list = new List<int> { 1, 3, 5, 7, 9 };
int index = list.BinarySearch(5); // retourne 2
8. Fusion de deux listes
var list1 = new List<int> { 1, 2, 3 };
var list2 = new List<int> { 4, 5, 6 };
list1.AddRange(list2); // [1,2,3,4,5,6]
9. Trouver les éléments communs entre deux listes
var list1 = new List<int> { 1, 2, 3, 4 };
var list2 = new List<int> { 3, 4, 5, 6 };
var common = list1.Intersect(list2).ToList(); // [3,4]
10. Rotation d’une liste (décaler les éléments)
Exemple : [1,2,3,4,5] → [5,1,2,3,4]
var list = new List<int> { 1, 2, 3, 4, 5 };
int last = list[list.Count - 1];
list.RemoveAt(list.Count - 1);
list.Insert(0, last);
Aucun commentaire:
Enregistrer un commentaire