Salut ! Aujourd'hui, on va plonger dans un sujet fondamental en Dart : les collections. Si tu codes en Dart (et donc probablement en Flutter), tu manipules des collections tout le temps - des listes de produits, des maps de configurations, des sets d'IDs uniques...
Le truc, c'est que Dart offre des méthodes ultra-puissantes pour manipuler les collections de façon élégante. Mais beaucoup de développeurs passent à côté et écrivent du code verbeux avec des boucles for partout.
Dans cet article, je vais te montrer comment utiliser les collections comme un ninja. Tu vas découvrir des méthodes que tu ne connaissais peut-être pas, comprendre quand utiliser List vs Set vs Map, et surtout, écrire du code plus concis et plus performant.
Prêt à devenir un magicien des collections ? C'est parti ! 🚀
Les trois types de collections
Avant de plonger dans les détails, comprenons bien les différences entre les trois types principaux de collections en Dart.
List : la collection ordonnée
Une List est comme un tableau. Elle stocke des éléments dans un ordre précis et permet les doublons.
Quand l'utiliser ?
-
Tu veux garder l'ordre d'insertion
-
Tu as besoin d'accéder aux éléments par index
-
Les doublons, c'est ok pour toi
Exemple d'usage : Une liste de messages dans un chat, une file d'attente de tâches, un historique de navigation.
List<String> messages = [
'Bonjour',
'Comment ça va ?',
'Bonjour', // Doublon autorisé
];
print(messages[0]); // Accès par index
print(messages.length); // Taille de la liste
Set : la collection d'éléments uniques
Un Set c'est cool parce que ça te garantit qu'il y a pas de doublons. L'ordre n'est pas garanti (sauf avec LinkedHashSet).
Quand l'utiliser ?
-
Tu veux éliminer les doublons automatiquement
-
Tu fais beaucoup de vérifications d'existence (
contains) -
Tu veux faire des opérations mathématiques (union, intersection)
Exemple d'usage : Liste d'IDs uniques, tags associés à un article, ensemble de permissions.
Set<String> tags = {'dart', 'flutter', 'mobile'};
tags.add('dart'); // Ignoré car déjà présent
print(tags.length); // 3
// Vérifier si un truc existe - super rapide !
bool contient = tags.contains('flutter'); // true
Map : la collection clé-valeur
Une Map (ou dictionnaire) c'est ta meilleure amie quand tu dois associer des clés à des valeurs. C'est parfait pour des lookups rapides.
Quand l'utiliser ?
-
T'as des paires clé-valeur
-
Tu veux accéder vite à une valeur via sa clé
-
Tu modélises des configs, des traductions, des caches
Exemple d'usage : Configuration d'app, données d'utilisateur structurées, cache de résultats.
Map<String, int> ages = {
'Alice': 25,
'Bob': 30,
'Charlie': 35,
};
print(ages['Alice']); // Accès super rapide
List : bien plus qu'un simple tableau
Commençons par explorer les List en profondeur. Dart offre deux types de listes : les listes qui peuvent grandir (growable) et les listes à taille fixe.
Créer des listes
// Liste vide (peut grandir)
List<int> nombres = [];
// Liste avec des valeurs
List<String> fruits = ['Pomme', 'Banane', 'Orange'];
// Liste typée explicitement
List<double> prix = [9.99, 14.50, 7.25];
// Liste avec le type deviné
var couleurs = ['Rouge', 'Vert', 'Bleu'];
// Liste à taille fixe (attention !)
List<int> fixe = List.filled(5, 0); // [0, 0, 0, 0, 0]
// fixe.add(1); // ERREUR : taille fixe, tu peux pas ajouter
// Liste générée
List<int> carres = List.generate(5, (index) => index * index);
// [0, 1, 4, 9, 16]
La différence entre liste variable et fixe c'est important. Une liste créée avec List.filled() ne peut pas grandir ou rétrécir. Si tu essaies d'ajouter un élément, ton app va crasher.
Accéder aux éléments
List<String> fruits = ['Pomme', 'Banane', 'Orange', 'Mangue'];
// Par index
print(fruits[0]); // Pomme
print(fruits[2]); // Orange
// Premier et dernier
print(fruits.first); // Pomme
print(fruits.last); // Mangue
// Pas d'index négatifs en Dart, mais tu peux faire :
print(fruits[fruits.length - 1]); // Dernier élément
// Accès sécurisé (évite les crashs)
String? element = fruits.length > 5 ? fruits[5] : null;
// Sous-liste (range)
List<String> sousListe = fruits.sublist(1, 3); // ['Banane', 'Orange']
Attention aux accès hors limites ! Si tu essaies fruits[10] sur une liste de 4 éléments, ton app va crasher direct. Toujours bien vérifier avant ou utiliser des méthodes sécurisées.
Modifier des listes
List<String> taches = ['Coder', 'Tester'];
// Ajouter un élément
taches.add('Déployer');
print(taches); // ['Coder', 'Tester', 'Déployer']
// Ajouter plusieurs
taches.addAll(['Documenter', 'Réviser']);
// Insérer à une position spécifique
taches.insert(1, 'Débugger');
print(taches); // ['Coder', 'Débugger', 'Tester', ...]
// Modifier un élément
taches[0] = 'Coder mieux';
// Retirer un élément
taches.remove('Tester'); // Retire la première occurrence
taches.removeAt(0); // Retire par index
taches.removeLast(); // Retire le dernier
// Retirer selon condition
taches.removeWhere((tache) => tache.contains('Dé'));
// Vider complètement
taches.clear();
Chercher des trucs
List<int> nombres = [5, 2, 8, 2, 9, 3, 8];
// Vérifier si c'est là
bool contient = nombres.contains(8); // true
// Trouver à quel endroit
int index = nombres.indexOf(8); // 2 (première occurrence)
int dernierIndex = nombres.lastIndexOf(8); // 6
// Index avec condition perso
int indexCondition = nombres.indexWhere((n) => n > 7); // 2 (le 8)
// Vérifier si tous/certains respectent une condition
bool tousPositifs = nombres.every((n) => n > 0); // true
bool certains = nombres.any((n) => n > 10); // false
Ces méthodes sont sympas mais attention à la perf. contains() et indexOf() parcourent la liste au pire. Si tu cherches beaucoup, un Set ou une Map c'est plus rapide.
Transformer des listes : map, where, reduce
C'est ici que ça devient vraiment cool. Au lieu d'écrire des boucles for partout, tu peux utiliser des méthodes qui rendent ton code plus lisible et concis.
map : Transformer chaque élément
map() applique une fonction à chaque élément et te retourne une nouvelle collection.
List<int> nombres = [1, 2, 3, 4, 5];
// Doubler chaque nombre
List<int> doubles = nombres.map((n) => n * 2).toList();
print(doubles); // [2, 4, 6, 8, 10]
// Transformer vers un autre type
List<String> textes = nombres.map((n) => 'Numéro $n').toList();
print(textes); // ['Numéro 1', 'Numéro 2', ...]
Important : map() te retourne un Iterable, pas une List. Tu dois appeler .toList() pour avoir une vraie liste.
Exemple concret : Transformer des données d'API
// Données brutes de l'API
List<Map<String, dynamic>> apiData = [
{'id': 1, 'name': 'Alice', 'age': 25},
{'id': 2, 'name': 'Bob', 'age': 30},
{'id': 3, 'name': 'Charlie', 'age': 35},
];
// Créer une classe Utilisateur
class Utilisateur {
final int id;
final String nom;
final int age;
Utilisateur({required this.id, required this.nom, required this.age});
@override
String toString() => 'Utilisateur(id: $id, nom: $nom, age: $age)';
}
// Transformer en objets Utilisateur
List<Utilisateur> utilisateurs = apiData.map((json) {
return Utilisateur(
id: json['id'],
nom: json['name'],
age: json['age'],
);
}).toList();
print(utilisateurs);
// [Utilisateur(id: 1, nom: Alice, age: 25), ...]
// Extraire juste les noms
List<String> noms = utilisateurs.map((u) => u.nom).toList();
print(noms); // ['Alice', 'Bob', 'Charlie']
where : Filtrer les éléments
where() te garde seulement les éléments qui respectent ta condition.
List<int> nombres = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// Garder seulement les pairs
List<int> pairs = nombres.where((n) => n % 2 == 0).toList();
print(pairs); // [2, 4, 6, 8, 10]
// Garder les nombres > 5
List<int> grands = nombres.where((n) => n > 5).toList();
print(grands); // [6, 7, 8, 9, 10]
Exemple concret : Filtrer des produits
class Produit {
final String nom;
final double prix;
final bool enStock;
Produit(this.nom, this.prix, this.enStock);
}
List<Produit> produits = [
Produit('Laptop', 999.99, true),
Produit('Souris', 25.50, true),
Produit('Clavier', 75.00, false),
Produit('Écran', 299.99, true),
Produit('Webcam', 89.99, false),
];
// Produits en stock
List<Produit> disponibles = produits
.where((p) => p.enStock)
.toList();
// Produits en stock ET moins de 100€
List<Produit> abordables = produits
.where((p) => p.enStock && p.prix < 100)
.toList();
print('${abordables.length} produits cool et pas chers');
// 1 produits cool et pas chers (Souris)
Combiner map et where
Tu peux enchaîner les méthodes pour créer des pipelines super puissants.
List<int> nombres = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// Filtrer puis transformer
List<int> resultat = nombres
.where((n) => n % 2 == 0) // Garder les pairs
.map((n) => n * n) // Mettre au carré
.toList();
print(resultat); // [4, 16, 36, 64, 100]
// Attention à l'ordre !
// where puis map = plus efficace (moins de choses à transformer)
// map puis where = moins efficace (transforme tout puis filtre)
Exemple concret : Préparer des données pour l'UI
class Utilisateur {
final int id;
final String nom;
final bool actif;
final int age;
Utilisateur(this.id, this.nom, this.actif, this.age);
}
List<Utilisateur> users = [
Utilisateur(1, 'alice', true, 25),
Utilisateur(2, 'bob', false, 30),
Utilisateur(3, 'charlie', true, 35),
Utilisateur(4, 'david', true, 28),
];
// Pour l'écran, on veut :
// 1. Seulement les utilisateurs actifs
// 2. Nom en majuscules
// 3. Format "NOM (âge ans)"
List<String> affichage = users
.where((u) => u.actif)
.map((u) => '${u.nom.toUpperCase()} (${u.age} ans)')
.toList();
print(affichage);
// ['ALICE (25 ans)', 'CHARLIE (35 ans)', 'DAVID (28 ans)']
reduce et fold : Agréger tout
reduce() et fold() c'est pour quand tu veux combiner tous les éléments en une seule valeur.
List<int> nombres = [1, 2, 3, 4, 5];
// reduce : combine les éléments deux par deux
int somme = nombres.reduce((total, element) => total + element);
print(somme); // 15
int produit = nombres.reduce((prod, element) => prod * element);
print(produit); // 120
// fold : comme reduce mais avec valeur de départ
int sommeAvecInitiale = nombres.fold(0, (total, element) => total + element);
print(sommeAvecInitiale); // 15
// fold est plus flexible
String concatene = nombres.fold('', (texte, n) => '$texte$n');
print(concatene); // '12345'
Différence clé : reduce() a besoin d'au moins un élément et retourne le même type. fold() peut gérer une liste vide et peut retourner un type différent.
Exemple concret : Calculer un total de panier
class Article {
final String nom;
final double prix;
final int quantite;
Article(this.nom, this.prix, this.quantite);
double get sousTotal => prix * quantite;
}
List<Article> panier = [
Article('Laptop', 999.99, 1),
Article('Souris', 25.50, 2),
Article('Clavier', 75.00, 1),
];
// Calculer le total
double total = panier.fold(0.0, (somme, article) => somme + article.sousTotal);
print('Total du panier: ${total.toStringAsFixed(2)}€');
// Total du panier: 1125.99€
// Compter le nombre d'articles
int nombreArticles = panier.fold(0, (total, article) => total + article.quantite);
print('$nombreArticles articles dans le panier');
// 4 articles dans le panier
Set : garantir l'unicité
Passons maintenant aux Set. Leur super-pouvoir ? Garantir que chaque élément est unique.
Créer et manipuler des Sets
// Créer un set vide
Set<String> tags = {};
// Attention : {} seul crée une Map, pas un Set !
// Utilise <String>{} pour être explicite
// Créer avec des valeurs
Set<int> nombres = {1, 2, 3, 4, 5};
// À partir d'une liste (élimine les doublons)
List<int> avecDoublons = [1, 2, 2, 3, 3, 3, 4, 5, 5];
Set<int> uniques = avecDoublons.toSet();
print(uniques); // {1, 2, 3, 4, 5}
// Ajouter des éléments
tags.add('dart');
tags.add('flutter');
tags.add('dart'); // Ignoré car déjà là
print(tags.length); // 2
// Ajouter plusieurs
tags.addAll(['mobile', 'développement']);
Opérations d'ensemble
C'est là que les Sets sont vraiment malades. Tu peux faire des opérations mathématiques d'ensemble.
Set<int> a = {1, 2, 3, 4, 5};
Set<int> b = {4, 5, 6, 7, 8};
// Union : tous les éléments des deux
Set<int> union = a.union(b);
print(union); // {1, 2, 3, 4, 5, 6, 7, 8}
// Intersection : que ce qui est dans les deux
Set<int> intersection = a.intersection(b);
print(intersection); // {4, 5}
// Différence : ce qui est dans A mais pas B
Set<int> difference = a.difference(b);
print(difference); // {1, 2, 3}
Exemple concret : Gestion de permissions
class Utilisateur {
final String nom;
final Set<String> permissions;
Utilisateur(this.nom, this.permissions);
bool peutFaire(String action) {
return permissions.contains(action);
}
void ajouterPermission(String permission) {
permissions.add(permission);
}
}
// Définir des rôles avec leurs permissions
final adminPermissions = {
'lire',
'écrire',
'supprimer',
'gérer_utilisateurs',
};
final editorPermissions = {
'lire',
'écrire',
};
final readerPermissions = {
'lire',
};
// Créer des utilisateurs
var admin = Utilisateur('Alice', {...adminPermissions});
var editor = Utilisateur('Bob', {...editorPermissions});
// Vérifier les permissions
print(admin.peutFaire('supprimer')); // true
print(editor.peutFaire('supprimer')); // false
// Trouver les permissions communes
Set<String> communesAdminEditor =
adminPermissions.intersection(editorPermissions);
print('Permissions communes: $communesAdminEditor');
// {lire, écrire}
// Permissions exclusives à admin
Set<String> exclusivesAdmin =
adminPermissions.difference(editorPermissions);
print('Exclusives admin: $exclusivesAdmin');
// {supprimer, gérer_utilisateurs}
Éliminer les doublons facilement
C'est un cas d'usage super courant : tu as une liste avec des doublons et tu veux les nettoyer.
List<String> messagesAvecDoublons = [
'Bonjour',
'Comment ça va ?',
'Bonjour',
'Très bien merci',
'Comment ça va ?',
'Super !',
];
// Méthode 1 : Convertir en Set puis en List
List<String> uniques = messagesAvecDoublons.toSet().toList();
print(uniques); // ['Bonjour', 'Comment ça va ?', 'Très bien merci', 'Super !']
// Méthode 2 : Garder l'ordre avec LinkedHashSet
Set<String> set = LinkedHashSet.from(messagesAvecDoublons);
List<String> uniquesOrdonnees = set.toList();
Performance : La conversion toSet() est très rapide. Pour vérifier si un élément existe, un Set c'est O(1) alors qu'une List c'est O(n).
Map : la puissance des paires clé-valeur
Les Map c'est extraordinairement utile. Elles permettent d'associer des clés uniques à des valeurs.
Créer et accéder aux Maps
// Map vide
Map<String, int> scores = {};
// Map avec des valeurs
Map<String, String> traductions = {
'hello': 'bonjour',
'goodbye': 'au revoir',
'thanks': 'merci',
};
// Accéder à une valeur
String? bonjour = traductions['hello'];
print(bonjour); // 'bonjour'
// Valeur par défaut si clé inexistante
String merci = traductions['thanks'] ?? 'valeur par défaut';
// Modifier une valeur
traductions['hello'] = 'salut';
// Ajouter une nouvelle paire
traductions['yes'] = 'oui';
// Supprimer une clé
traductions.remove('goodbye');
Méthodes utiles
Map<String, int> ages = {
'Alice': 25,
'Bob': 30,
'Charlie': 35,
};
// Vérifier l'existence d'une clé
bool contientAlice = ages.containsKey('Alice'); // true
bool contient25 = ages.containsValue(25); // true
// Obtenir toutes les clés ou valeurs
List<String> noms = ages.keys.toList();
List<int> agesListe = ages.values.toList();
// Nombre d'éléments
int taille = ages.length;
// Vider la map
ages.clear();
Itérer sur une Map
Il y a plusieurs façons de faire, selon ce que tu veux.
Map<String, int> scores = {
'Alice': 95,
'Bob': 87,
'Charlie': 92,
};
// Méthode 1 : forEach
scores.forEach((nom, score) {
print('$nom a obtenu $score points');
});
// Méthode 2 : for-in sur les entries
for (var entry in scores.entries) {
print('${entry.key}: ${entry.value}');
}
// Méthode 3 : for-in sur les clés
for (var nom in scores.keys) {
print('$nom: ${scores[nom]}');
}
// Transformer en liste
List<String> resultats = scores.entries
.map((e) => '${e.key} a eu ${e.value}/100')
.toList();
Grouper des données avec Map
Un pattern super utile : grouper des éléments par catégorie.
class Produit {
final String nom;
final String categorie;
final double prix;
Produit(this.nom, this.categorie, this.prix);
}
List<Produit> produits = [
Produit('Laptop', 'Électronique', 999.99),
Produit('Souris', 'Électronique', 25.50),
Produit('Bureau', 'Mobilier', 299.99),
Produit('Chaise', 'Mobilier', 149.99),
Produit('Clavier', 'Électronique', 75.00),
];
// Grouper par catégorie
Map<String, List<Produit>> parCategorie = {};
for (var produit in produits) {
// Si la catégorie n'existe pas, créer une liste vide
parCategorie.putIfAbsent(produit.categorie, () => []);
parCategorie[produit.categorie]!.add(produit);
}
// Afficher
parCategorie.forEach((categorie, produits) {
print('\n$categorie (${produits.length} produits):');
for (var p in produits) {
print(' - ${p.nom}: ${p.prix}€');
}
});
// Output:
// Électronique (3 produits):
// - Laptop: 999.99€
// - Souris: 25.50€
// - Clavier: 75.0€
//
// Mobilier (2 produits):
// - Bureau: 299.99€
// - Chaise: 149.99€
Compter les occurrences
Un autre pattern classique : compter combien de fois chaque élément apparaît.
List<String> votes = [
'Rouge', 'Bleu', 'Rouge', 'Vert',
'Rouge', 'Bleu', 'Jaune', 'Rouge',
'Vert', 'Rouge', 'Bleu', 'Rouge',
];
// Compter les votes
Map<String, int> compteur = {};
for (var vote in votes) {
compteur[vote] = (compteur[vote] ?? 0) + 1;
}
print(compteur);
// {Rouge: 6, Bleu: 3, Vert: 2, Jaune: 1}
// Trouver le gagnant
String gagnant = '';
int maxVotes = 0;
compteur.forEach((couleur, votes) {
if (votes > maxVotes) {
maxVotes = votes;
gagnant = couleur;
}
});
print('Gagnant: $gagnant avec $maxVotes votes');
// Gagnant: Rouge avec 6 votes
Méthodes avancées et astuces
Maintenant qu'on a vu les bases, explorons des techniques plus avancées.
expand : Aplatir des listes imbriquées
expand() transforme une liste de listes en une seule liste plate.
List<List<int>> listes = [
[1, 2, 3],
[4, 5],
[6, 7, 8, 9],
];
// Aplatir en une seule liste
List<int> aplatie = listes.expand((liste) => liste).toList();
print(aplatie); // [1, 2, 3, 4, 5, 6, 7, 8, 9]
// Exemple pratique : extraire tous les tags de plusieurs articles
class Article {
final String titre;
final List<String> tags;
Article(this.titre, this.tags);
}
List<Article> articles = [
Article('Article 1', ['dart', 'flutter']),
Article('Article 2', ['mobile', 'ios']),
Article('Article 3', ['dart', 'backend']),
];
// Obtenir tous les tags uniques
Set<String> tousTags = articles
.expand((article) => article.tags)
.toSet();
print(tousTags); // {dart, flutter, mobile, ios, backend}
take, skip et leurs variantes
Ces méthodes c'est cool quand tu veux prendre ou sauter des éléments selon certains critères.
List<int> nombres = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// take : prendre les N premiers
List<int> premiers = nombres.take(3).toList();
print(premiers); // [1, 2, 3]
// skip : sauter les N premiers
List<int> apres = nombres.skip(7).toList();
print(apres); // [8, 9, 10]
// takeWhile : prendre tant que c'est vrai
List<int> petits = nombres.takeWhile((n) => n < 6).toList();
print(petits); // [1, 2, 3, 4, 5]
// skipWhile : sauter tant que c'est vrai
List<int> grands = nombres.skipWhile((n) => n < 6).toList();
print(grands); // [6, 7, 8, 9, 10]
Exemple d'utilisation : Pagination
class Pagination {
static List<T> getPage<T>(List<T> items, int page, int itemsParPage) {
return items
.skip(page * itemsParPage)
.take(itemsParPage)
.toList();
}
}
List<String> articles = [
'Article 1', 'Article 2', 'Article 3', 'Article 4',
'Article 5', 'Article 6', 'Article 7', 'Article 8',
'Article 9', 'Article 10',
];
// Page 0 (3 articles par page)
print(Pagination.getPage(articles, 0, 3));
// [Article 1, Article 2, Article 3]
// Page 1
print(Pagination.getPage(articles, 1, 3));
// [Article 4, Article 5, Article 6]
firstWhere et singleWhere
Ces méthodes c'est pour trouver des éléments selon une condition.
List<int> nombres = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// firstWhere : premier élément qui respecte la condition
int premierPair = nombres.firstWhere((n) => n % 2 == 0);
print(premierPair); // 2
// Avec valeur par défaut (orElse)
int premierGrand = nombres.firstWhere(
(n) => n > 20,
orElse: () => -1,
);
print(premierGrand); // -1 (aucun élément > 20)
// lastWhere : dernier élément qui respecte la condition
int dernierPair = nombres.lastWhere((n) => n % 2 == 0);
print(dernierPair); // 10
// singleWhere : s'assure qu'il y a exactement un élément
List<int> nombres2 = [1, 5, 3];
int cinq = nombres2.singleWhere((n) => n == 5);
print(cinq); // 5
// Si 0 ou plus de 1 élément → Exception
// nombres2.singleWhere((n) => n > 2); // ERREUR : 2 éléments (5 et 3)
Performance : choisir la bonne structure
Le choix entre List, Set et Map n'est pas qu'une question de préférence - ça affecte les performances.
Complexité des opérations
| Opération | List | Set | Map |
|---|---|---|---|
| Ajout (fin) | O(1) | O(1) | O(1) |
| Chercher | O(n) | O(1) | O(1) |
| Accès par index | O(1) | - | - |
| Accès par clé | - | - | O(1) |
| Suppression | O(n) | O(1) | O(1) |
Que signifient ces notations ?
-
O(1) : Temps constant, super rapide peu importe la taille
-
O(n) : Temps proportionnel à la taille, plus lent si c'est big
En pratique :
-
Si tu cherches beaucoup avec
contains()→ utilise un Set -
Si t'as des paires clé-valeur et tu cherches par clé → utilise une Map
-
Si tu as besoin d'ordre et d'accès par index → utilise une List
Exemple de comparaison
import 'dart:math';
void comparerPerformances() {
final random = Random();
// Créer 10000 nombres aléatoires
List<int> nombresListe = List.generate(10000, (_) => random.nextInt(1000));
Set<int> nombresSet = nombresListe.toSet();
// Test : chercher 1000 fois si un nombre existe
final debut1 = DateTime.now();
for (int i = 0; i < 1000; i++) {
nombresListe.contains(500);
}
final duree1 = DateTime.now().difference(debut1);
final debut2 = DateTime.now();
for (int i = 0; i < 1000; i++) {
nombresSet.contains(500);
}
final duree2 = DateTime.now().difference(debut2);
print('List.contains: ${duree1.inMicroseconds}µs');
print('Set.contains: ${duree2.inMicroseconds}µs');
print('Set est ${duree1.inMicroseconds / duree2.inMicroseconds}x plus rapide');
}
Sur ma machine, Set est genre 100x plus rapide pour les recherches !
Bonnes pratiques
Terminons avec des conseils pour utiliser les collections comme tu dois.
1. Utilise const pour les collections immuables
// ❌ Mauvais : collection recréée à chaque fois
List<String> getCouleurs() {
return ['Rouge', 'Vert', 'Bleu'];
}
// ✅ Bon : collection constante, créée une seule fois
const List<String> COULEURS = ['Rouge', 'Vert', 'Bleu'];
2. Préfère les méthodes fonctionnelles aux boucles
// ❌ Verbeux
List<int> doubles = [];
for (var n in nombres) {
doubles.add(n * 2);
}
// ✅ Concis et lisible
List<int> doubles = nombres.map((n) => n * 2).toList();
3. Utilise l'opérateur spread pour combiner
List<int> a = [1, 2, 3];
List<int> b = [4, 5, 6];
// ❌ Mauvais
List<int> combine = [];
combine.addAll(a);
combine.addAll(b);
// ✅ Bon
List<int> combine = [...a, ...b];
// Avec condition
bool includeB = true;
List<int> combine2 = [
...a,
if (includeB) ...b,
];
4. Gère les collections nullables proprement
List<String>? maybeListe;
// ❌ Peut crasher
int longueur = maybeListe.length;
// ✅ Sécurisé
int longueur = maybeListe?.length ?? 0;
// Itérer en toute sécurité
for (var item in maybeListe ?? []) {
print(item);
}
Conclusion
Les collections c'est vraiment le coeur de tout ce que tu codes en Dart. Les maîtriser te permet d'écrire du code plus lisible, plus rapide et plus court.
Points clés à retenir :
-
List : Ordre, accès par index, peut avoir des doublons
-
Set : Unicité garantie, recherche super rapide, opérations d'ensemble
-
Map : Paires clé-valeur, lookup rapide
Méthodes essentielles :
-
map()pour transformer -
where()pour filtrer -
reduce()etfold()pour agréger -
expand()pour aplatir -
firstWhere()pour chercher
Performance :
-
Set et Map : O(1) pour recherche/ajout/suppression
-
List : O(1) pour accès par index, O(n) pour recherche
Maintenant, va écrire du code plus cool avec ces méthodes !
Pour approfondir :
T'as des questions sur les collections ? Balance-les dans les commentaires !
Articles connexes:

Laisser un commentaire