Détails
Suppression des valeurs en double dans un tableau JS
J'ai un tableau JavaScript très simple qui peut ou non contenir des doublons.
var names = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"];
Je dois supprimer les doublons et placer les valeurs uniques dans un nouveau tableau.
Je pourrais vous indiquer tous les codes que j'ai essayés mais je pense que cela ne sert à rien car ils ne fonctionnent pas. J'accepte également les solutions jQuery.
Question similaire :
1217
3
TL;DR
Utilisation du constructeur [Set][1] et de la [syntaxe de propagation][2] :
"Intelligent" mais naïf
En gros, on itère sur le tableau et, pour chaque élément, on vérifie si la première position de cet élément dans le tableau est égale à la position courante. Évidemment, ces deux positions sont différentes pour les éléments dupliqués.
En utilisant le 3ème paramètre ("ce tableau") de la callback du filtre, nous pouvons éviter une fermeture de la variable tableau :
Bien que concis, cet algorithme n'est pas particulièrement efficace pour les grands tableaux (temps quadratique).
Les tables de hachage à la rescousse
C'est ainsi que l'on procède généralement. L'idée est de placer chaque élément dans une table de hachage, puis de vérifier sa présence instantanément. Cela nous donne un temps linéaire, mais présente au moins deux inconvénients :
uniq([1, "1"])
ne retournera que[1]
.uniq([{foo:1},{foo:2}])
retournera juste[{foo:1}]
.Cela dit, si vos tableaux ne contiennent que des primitives et que vous ne vous souciez pas des types (par exemple, il s'agit toujours de nombres), cette solution est optimale.
Le meilleur de deux mondes
Une solution universelle combine les deux approches : elle utilise des recherches de hachage pour les primitives et une recherche linéaire pour les objets.
trier | uniq
Une autre option consiste à trier le tableau en premier, puis à supprimer chaque élément égal au précédent :
Encore une fois, cela ne fonctionne pas avec les objets (car tous les objets sont égaux pour
sort
). De plus, nous modifions silencieusement le tableau original en tant qu'effet secondaire - ce n'est pas bon ! Cependant, si votre entrée est déjà triée, c'est la solution (enlevez simplementsort
de l'exemple ci-dessus).Unique par...
Parfois, il est souhaitable d'unifier une liste en se basant sur des critères autres que l'égalité, par exemple, pour filtrer les objets qui sont différents, mais qui partagent une propriété. Cela peut être fait de manière élégante en passant un callback. Ce callback "key" est appliqué à chaque élément, et les éléments avec des "keys" égaux sont supprimés. Puisque
key
est censé retourner une primitive, la table de hachage fonctionnera bien ici :Une
key()
particulièrement utile estJSON.stringify
qui supprimera les objets qui sont physiquement différents, mais qui ont la même apparence :Si la
key
n'est pas primitive, vous devez recourir à la recherche linéaire :En ES6, vous pouvez utiliser un
Set
:ou un
Map
:qui fonctionnent également avec des clés non primitives.
Première ou dernière ?
Lorsque vous supprimez des objets par une clé, vous pouvez vouloir garder le premier des objets "égaux" ou le dernier.
Utilisez la variante
Set
ci-dessus pour garder le premier, et la varianteMap
pour garder le dernier :Bibliothèques
underscore et Lo-Dash fournissent toutes deux des méthodes
uniq
. Leurs algorithmes sont fondamentalement similaires au premier extrait ci-dessus et se résument à ceci :C'est quadratique, mais il y a de belles choses en plus, comme l'intégration du
indexOf
natif, la possibilité d'uniqifier par une clé (iteratee
dans leur jargon), et des optimisations pour les tableaux déjà triés.Si vous utilisez jQuery et que vous ne supportez rien qui ne soit précédé d'un dollar, voici comment ça se passe :
qui est, encore une fois, une variation du premier extrait.
Performance
Les appels de fonction sont coûteux en JavaScript, donc les solutions ci-dessus, aussi concises soient-elles, ne sont pas particulièrement efficaces. Pour des performances maximales, remplacez
filter
par une boucle et supprimez les autres appels de fonction :Ce morceau de code laid fait la même chose que le snippet #3 ci-dessus, mais un ordre de grandeur plus rapide (en 2017, il n'est que deux fois plus rapide - les gens du noyau JS font un excellent travail !).
ES6
ES6 fournit l'objet Set, qui rend les choses beaucoup plus faciles :
ou
Notez que, contrairement à python, les ensembles ES6 sont itérés dans l'ordre d'insertion, donc ce code préserve l'ordre du tableau original.
Cependant, si vous avez besoin d'un tableau avec des éléments uniques, pourquoi ne pas utiliser les sets dès le début ?
Générateurs
Une version "paresseuse", basée sur des générateurs, de
uniq
peut être construite sur la même base :[1] : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set [2] : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax
Rapide et sale en utilisant jQuery :
Vanilla JS : Suppression des doublons en utilisant un objet comme un ensemble.
Vous pouvez toujours essayer de le mettre dans un objet, puis d'itérer à travers ses clés :
Vanilla JS : Suppression des doublons par le suivi des valeurs déjà vues (order-safe)
Ou, pour une version plus sûre, utilisez un objet pour stocker toutes les valeurs déjà vues, et vérifiez les valeurs par rapport à cet objet avant de les ajouter à un tableau.
ECMAScript 6 : utilisation de la nouvelle structure de données Set (order-safe).
ECMAScript 6 ajoute la nouvelle structure de données
Set
, qui vous permet de stocker des valeurs de n'importe quel type.Set.values
renvoie les éléments dans l'ordre d'insertion.Exemple d'utilisation: