Introduction au filtrage de Map
Les Map en JavaScript sont des structures de données puissantes qui stockent des paires clé-valeur. Contrairement aux objets classiques, les Map préservent l'ordre d'insertion et peuvent utiliser n'importe quel type comme clé. Cependant, contrairement aux tableaux qui disposent de la méthode filter(), les Map n'ont pas de méthode de filtrage intégrée. Dans ce guide complet, nous allons explorer différentes techniques pour filtrer un Map en JavaScript selon les clés, les valeurs, ou des conditions complexes.
Méthode 1 : Filtrer par valeurs
La méthode la plus courante pour filtrer un Map consiste à convertir les entrées en tableau, filtrer ce tableau, puis créer un nouveau Map. Commençons par filtrer selon les valeurs :
const monMap = new Map([
['pomme', 5],
['banane', 3],
['cerise', 8],
['datte', 2],
['ananas', 10]
]);
const fruitsFiltres = new Map(
[...monMap.entries()].filter(([cle, valeur]) => valeur > 5)
);
console.log(fruitsFiltres);
const fruitsRares = new Map(
[...monMap.entries()].filter(([cle, valeur]) => valeur < 4)
);
console.log(fruitsRares);
Explication
L'opérateur de décomposition [...monMap.entries()] convertit le Map en tableau de paires [clé, valeur]. La méthode filter() prend une fonction de callback qui reçoit chaque entrée (déstructurée en [cle, valeur]) et retourne true pour conserver l'élément ou false pour l'exclure. Enfin, nous créons un nouveau Map à partir du tableau filtré.
Méthode 2 : Filtrer par clés
Vous pouvez également filtrer un Map en fonction des clés plutôt que des valeurs :
const fruitsEnC = new Map(
[...monMap.entries()].filter(([cle, valeur]) => cle.startsWith('c'))
);
console.log(fruitsEnC);
const fruitsAvecAn = new Map(
[...monMap.entries()].filter(([cle, valeur]) => cle.includes('an'))
);
console.log(fruitsAvecAn);
const fruitsLongs = new Map(
[...monMap.entries()].filter(([cle, valeur]) => cle.length > 5)
);
console.log(fruitsLongs);
Méthode 3 : Filtrer avec des conditions complexes
Vous pouvez combiner plusieurs conditions pour créer des filtres plus complexes :
const fruitsFiltresComplexes = new Map(
[...monMap.entries()].filter(([cle, valeur]) =>
valeur > 5 && cle.startsWith('a')
)
);
console.log(fruitsFiltresComplexes);
const fruitsMultiConditions = new Map(
[...monMap.entries()].filter(([cle, valeur]) =>
(valeur >= 3 && valeur <= 7) || cle.length === 6
)
);
console.log(fruitsMultiConditions);
Créer une fonction réutilisable
Pour une meilleure organisation du code, créons une fonction utilitaire générique :
function filtrerMap(map, predicat) {
return new Map(
[...map.entries()].filter(([cle, valeur]) => predicat(cle, valeur))
);
}
const fruitsChers = filtrerMap(monMap, (cle, valeur) => valeur > 5);
const fruitsAvecA = filtrerMap(monMap, (cle, valeur) => cle.includes('a'));
const fruitsSpeciaux = filtrerMap(monMap, (cle, valeur) =>
valeur >= 3 && cle.length > 5
);
Fonction avancée avec options
Voici une version plus avancée qui permet de filtrer par clé, valeur, ou les deux :
function filtrerMapAvance(map, options = {}) {
const {
filtreCle = null,
filtreValeur = null,
filtreComplet = null
} = options;
const predicat = (cle, valeur) => {
if (filtreComplet) {
return filtreComplet(cle, valeur);
}
const passeCle = filtreCle ? filtreCle(cle) : true;
const passeValeur = filtreValeur ? filtreValeur(valeur) : true;
return passeCle && passeValeur;
};
return new Map(
[...map.entries()].filter(([cle, valeur]) => predicat(cle, valeur))
);
}
const parValeur = filtrerMapAvance(monMap, {
filtreValeur: (valeur) => valeur > 5
});
const parCle = filtrerMapAvance(monMap, {
filtreCle: (cle) => cle.startsWith('a')
});
const parLesDeux = filtrerMapAvance(monMap, {
filtreCle: (cle) => cle.length > 5,
filtreValeur: (valeur) => valeur >= 3
});
const avecFonction = filtrerMapAvance(monMap, {
filtreComplet: (cle, valeur) => cle.includes('a') && valeur % 2 === 0
});
Filtrer un Map d'objets
Lorsque vous travaillez avec un Map contenant des objets comme valeurs, vous pouvez filtrer en fonction des propriétés de ces objets :
const utilisateurs = new Map([
['user1', { nom: 'Alice', age: 30, actif: true }],
['user2', { nom: 'Bob', age: 25, actif: false }],
['user3', { nom: 'Charlie', age: 35, actif: true }],
['user4', { nom: 'Diana', age: 28, actif: true }]
]);
const utilisateursActifs = new Map(
[...utilisateurs.entries()].filter(([cle, valeur]) => valeur.actif)
);
console.log(utilisateursActifs);
const utilisateursAges = new Map(
[...utilisateurs.entries()].filter(([cle, valeur]) => valeur.age > 30)
);
const utilisateursFiltres = new Map(
[...utilisateurs.entries()].filter(([cle, valeur]) =>
valeur.actif && valeur.age > 28
)
);
Cas d'usage pratiques
Scénario 1 : Filtrer des scores élevés
const scores = new Map([
['Alice', 95],
['Bob', 87],
['Charlie', 92],
['Diana', 88],
['Eve', 75]
]);
const meilleursJoueurs = new Map(
[...scores.entries()].filter(([nom, score]) => score > 85)
);
console.log(meilleursJoueurs);
Scénario 2 : Filtrer des produits en stock
const produits = new Map([
['laptop', { prix: 999, stock: 5 }],
['souris', { prix: 25, stock: 0 }],
['clavier', { prix: 75, stock: 12 }],
['écran', { prix: 200, stock: 3 }]
]);
const produitsDisponibles = new Map(
[...produits.entries()].filter(([nom, produit]) => produit.stock > 0)
);
const produitsAccessibles = new Map(
[...produits.entries()].filter(([nom, produit]) =>
produit.stock > 0 && produit.prix < 100
)
);
Scénario 3 : Filtrer des données par date
const evenements = new Map([
['event1', { date: new Date('2024-01-15'), titre: 'Conférence' }],
['event2', { date: new Date('2024-02-20'), titre: 'Workshop' }],
['event3', { date: new Date('2024-03-10'), titre: 'Meetup' }],
['event4', { date: new Date('2024-04-05'), titre: 'Séminaire' }]
]);
const aujourdhui = new Date('2024-02-01');
const evenementsFuturs = new Map(
[...evenements.entries()].filter(([id, event]) =>
event.date > aujourdhui
)
);
console.log(evenementsFuturs);
Le filtrage d'un Map a une complexité temporelle de O(n) où n est le nombre d'entrées. Voici quelques points à considérer :
Le filtrage crée un nouveau Map, donc il y a un coût en mémoire
Pour de très grandes collections, considérez d'utiliser une boucle for...of si vous n'avez besoin que d'itérer sur les résultats
Évitez les fonctions de filtrage trop complexes qui pourraient impacter les performances
Si vous devez filtrer fréquemment avec les mêmes critères, considérez de maintenir un Map filtré séparé
Chaînage de filtres
Vous pouvez chaîner plusieurs opérations de filtrage pour créer des filtres complexes :
const resultat = new Map(
[...monMap.entries()]
.filter(([cle, valeur]) => valeur > 3)
.filter(([cle, valeur]) => cle.length > 5)
.filter(([cle, valeur]) => cle.includes('a'))
);
const resultatOptimise = new Map(
[...monMap.entries()].filter(([cle, valeur]) =>
valeur > 3 && cle.length > 5 && cle.includes('a')
)
);
Astuce : Combiner plusieurs conditions dans un seul filter() est généralement plus performant que de chaîner plusieurs appels à filter(), car cela évite de créer des tableaux intermédiaires.
Conclusion
Nous avons couvert les aspects essentiels du filtrage de Map en JavaScript. Bien que les Map n'aient pas de méthode filter() intégrée, il est facile de les filtrer en les convertissant en tableaux. La méthode la plus courante consiste à utiliser l'opérateur de décomposition [...map.entries()], appliquer filter() avec une fonction de prédicat, puis créer un nouveau Map à partir du tableau filtré.
Le filtrage fonctionne efficacement pour les valeurs simples, les objets complexes, et peut être combiné avec d'autres opérations comme le tri ou la transformation. N'hésitez pas à créer vos propres fonctions utilitaires pour réutiliser vos filtres dans différents contextes de votre application.