Supprimer les valeurs en double du 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 mettre les valeurs uniques dans un nouveau tableau.

Je pourrais indiquer tous les codes que j’ai essayés mais je pense que c’est inutile parce qu’ils ne fonctionnent pas. J’accepte aussi les solutions jQuery.

Question similaire:

  • Obtenir toutes les valeurs non uniques (par exemple: dupliquer / plusieurs occurrences) dans un tableau

Rapide et sale en utilisant jQuery:

 var names = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"]; var uniqueNames = []; $.each(names, function(i, el){ if($.inArray(el, uniqueNames) === -1) uniqueNames.push(el); }); 

“Smart” mais façon naïve

 uniqueArray = a.filter(function(item, pos) { return a.indexOf(item) == pos; }) 

Fondamentalement, nous parcourons le tableau et, pour chaque élément, vérifions si la première position de cet élément dans le tableau est égale à la position actuelle. De toute évidence, ces deux positions sont différentes pour les éléments en double.

En utilisant le paramètre 3rd (“this array”) du rappel de filtre, nous pouvons éviter une fermeture de la variable de tableau:

 uniqueArray = a.filter(function(item, pos, self) { return self.indexOf(item) == pos; }) 

Bien que concis, cet algorithme n’est pas particulièrement efficace pour les grands tableaux (temps quadratique).

Hashtables à la rescousse

 function uniq(a) { var seen = {}; return a.filter(function(item) { return seen.hasOwnProperty(item) ? false : (seen[item] = true); }); } 

Voici comment cela se fait habituellement. 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 a au moins deux inconvénients:

  • comme les clés de hachage ne peuvent être que des chaînes en Javascript, ce code ne distingue pas les nombres et les “chaînes numériques”. En d’autres uniq([1,"1"]) , uniq([1,"1"]) renverra simplement [1]
  • pour la même raison, tous les objects seront considérés égaux: uniq([{foo:1},{foo:2}]) renverra simplement [{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 des objects.

 function uniq(a) { var prims = {"boolean":{}, "number":{}, "ssortingng":{}}, objs = []; return a.filter(function(item) { var type = typeof item; if(type in prims) return prims[type].hasOwnProperty(item) ? false : (prims[type][item] = true); else return objs.indexOf(item) >= 0 ? false : objs.push(item); }); } 

sortinger | uniq

Une autre option consiste à sortinger d’abord le tableau, puis à supprimer chaque élément égal au précédent:

 function uniq(a) { return a.sort().filter(function(item, pos, ary) { return !pos || item != ary[pos - 1]; }) } 

Encore une fois, cela ne fonctionne pas avec les objects (car tous les objects sont égaux pour le sort ). En outre, nous modifions silencieusement le tableau d’origine en un effet secondaire – pas bon! Cependant, si votre entrée est déjà sortingée, c’est la voie à suivre (il suffit de supprimer le sort ci-dessus).

Unique par …

Il est parfois souhaitable de désélectionner une liste basée sur certains critères autres que l’égalité, par exemple pour filtrer les objects différents, mais partager certaines propriétés. Cela peut être fait avec élégance en passant un rappel. Ce rappel “clé” est appliqué à chaque élément, et les éléments avec des “clés” égales sont supprimés. Comme la key doit renvoyer une primitive, la table de hachage fonctionnera correctement ici:

 function uniqBy(a, key) { var seen = {}; return a.filter(function(item) { var k = key(item); return seen.hasOwnProperty(k) ? false : (seen[k] = true); }) } 

Une key() particulièrement utile key() est JSON.ssortingngify qui supprime les objects physiquement différents, mais qui “ressemblent”:

 a = [[1,2,3], [4,5,6], [1,2,3]] b = uniqBy(a, JSON.ssortingngify) console.log(b) // [[1,2,3], [4,5,6]] 

Si la key n’est pas primitive, vous devez recourir à la recherche linéaire:

 function uniqBy(a, key) { var index = []; return a.filter(function (item) { var k = key(item); return index.indexOf(k) >= 0 ? false : index.push(k); }); } 

ou utilisez l’object Set dans ES6:

 function uniqBy(a, key) { var seen = new Set(); return a.filter(item => { var k = key(item); return seen.has(k) ? false : seen.add(k); }); } 

(Certaines personnes préfèrent !seen.has(k) && seen.add(k) au lieu de seen.has(k) ? false : seen.add(k) ).

Bibliothèques

Le soulignement et Lo-Dash fournissent tous deux des méthodes uniq . Leurs algorithmes sont fondamentalement similaires au premier extrait ci-dessus et se résument à ceci:

 var result = []; a.forEach(function(item) { if(result.indexOf(item) < 0) { result.push(item); } }); 

Ceci est quadratique, mais il y a de bonnes choses supplémentaires, comme l' indexOf natif, la possibilité d'unifier par une clé ( iteratee dans leur langage), et des optimisations pour des tableaux déjà sortingés.

Si vous utilisez jQuery et que vous ne supportez rien sans un dollar, cela se passe comme suit:

  $.uniqArray = function(a) { return $.grep(a, function(item, pos) { return $.inArray(item, a) === pos; }); } 

qui est, encore une fois, une variante du premier extrait.

Performance

Les appels de fonctions sont coûteux en Javascript, donc les solutions ci-dessus, aussi concises qu'elles soient, ne sont pas particulièrement efficaces. Pour des performances maximales, remplacez le filter par une boucle et supprimez les autres appels de fonction:

 function uniq_fast(a) { var seen = {}; var out = []; var len = a.length; var j = 0; for(var i = 0; i < len; i++) { var item = a[i]; if(seen[item] !== 1) { seen[item] = 1; out[j++] = item; } } return out; } 

Ce morceau de code laid fait la même chose que l'extrait de code n ° 3 ci-dessus, mais un ordre de grandeur plus rapide (en 2017, il n'est que deux fois plus rapide - les gens de base de JS font un excellent travail!)

 function uniq(a) { var seen = {}; return a.filter(function(item) { return seen.hasOwnProperty(item) ? false : (seen[item] = true); }); } function uniq_fast(a) { var seen = {}; var out = []; var len = a.length; var j = 0; for(var i = 0; i < len; i++) { var item = a[i]; if(seen[item] !== 1) { seen[item] = 1; out[j++] = item; } } return out; } ///// var r = [0,1,2,3,4,5,6,7,8,9], a = [], LEN = 1000, LOOPS = 1000; while(LEN--) a = a.concat(r); var d = new Date(); for(var i = 0; i < LOOPS; i++) uniq(a); document.write('
uniq, ms/loop: ' + (new Date() - d)/LOOPS) var d = new Date(); for(var i = 0; i < LOOPS; i++) uniq_fast(a); document.write('
uniq_fast, ms/loop: ' + (new Date() - d)/LOOPS)

Je suis fatigué de voir tous les mauvais exemples avec for-loops ou jQuery. Le Javascript dispose des outils parfaits pour cela: sortinger, cartographier et réduire.

Uniq réduit tout en gardant l’ordre existant

 var names = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"]; var uniq = names.reduce(function(a,b){ if (a.indexOf(b) < 0 ) a.push(b); return a; },[]); console.log(uniq, names) // [ 'Mike', 'Matt', 'Nancy', 'Adam', 'Jenny', 'Carl' ] // one liner return names.reduce(function(a,b){if(a.indexOf(b)<0)a.push(b);return a;},[]); 

Uniq plus rapide avec le sorting

Il y a probablement des moyens plus rapides mais celui-ci est assez décent.

 var uniq = names.slice() // slice makes copy of array before sorting it .sort(function(a,b){ return a > b; }) .reduce(function(a,b){ if (a.slice(-1)[0] !== b) a.push(b); // slice(-1)[0] means last item in array without removing it (like .pop()) return a; },[]); // this empty array becomes the starting value for a // one liner return names.slice().sort(function(a,b){return a > b}).reduce(function(a,b){if (a.slice(-1)[0] !== b) a.push(b);return a;},[]); 

Mise à jour 2015: version ES6:

Dans ES6, vous avez Sets et Spread, ce qui rend très facile et performant de supprimer tous les doublons:

 var uniq = [ ...new Set(names) ]; // [ 'Mike', 'Matt', 'Nancy', 'Adam', 'Jenny', 'Carl' ] 

Trier en fonction de l'occurrence:

Quelqu'un a demandé comment commander les résultats en fonction du nombre de noms uniques:

 var names = ['Mike', 'Matt', 'Nancy', 'Adam', 'Jenny', 'Nancy', 'Carl'] var uniq = names .map((name) => { return {count: 1, name: name} }) .reduce((a, b) => { a[b.name] = (a[b.name] || 0) + b.count return a }, {}) var sorted = Object.keys(uniq).sort((a, b) => uniq[a] < uniq[b]) console.log(sorted) 

Vanilla JS: Supprimer les doublons en utilisant un object comme un ensemble

Vous pouvez toujours essayer de le mettre dans un object, et ensuite parcourir ses clés:

 function remove_duplicates(arr) { var obj = {}; var ret_arr = []; for (var i = 0; i < arr.length; i++) { obj[arr[i]] = true; } for (var key in obj) { ret_arr.push(key); } return ret_arr; } 

Vanilla JS: supprime les doublons en suivant les valeurs déjà vues (ordre sécurisé)

Ou, pour une version sécurisée, utilisez un object pour stocker toutes les valeurs précédemment vues et vérifiez les valeurs par rapport à avant avant d'append à un tableau.

 function remove_duplicates_safe(arr) { var seen = {}; var ret_arr = []; for (var i = 0; i < arr.length; i++) { if (!(arr[i] in seen)) { ret_arr.push(arr[i]); seen[arr[i]] = true; } } return ret_arr; } 

ECMAScript 6: Utiliser la nouvelle structure de données Set (ordre sécurisé)

ECMAScript 6 ajoute le nouveau Set Data-Structure, qui vous permet de stocker des valeurs de tout type. Set.values renvoie des éléments dans l'ordre d'insertion.

 function remove_duplicates_es6(arr) { let s = new Set(arr); let it = s.values(); return Array.from(it); } 

Exemple d'utilisation:

 a = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"]; b = remove_duplicates(a); // b: // ["Adam", "Carl", "Jenny", "Matt", "Mike", "Nancy"] c = remove_duplicates_safe(a); // c: // ["Mike", "Matt", "Nancy", "Adam", "Jenny", "Carl"] d = remove_duplicates_es6(a); // d: // ["Mike", "Matt", "Nancy", "Adam", "Jenny", "Carl"] 

Utilisez Underscore.js

C’est une bibliothèque avec une foule de fonctions pour manipuler les tableaux.

C’est la cravate à suivre avec les tux de jQuery et les bretelles de Backbone.js.

_.uniq

_.uniq(array, [isSorted], [iterator]) Alias: unique
Produit une version sans duplicata du tableau , en utilisant === pour tester l’égalité des objects. Si vous savez à l’avance que le tableau est sortingé, le passage à true pour isSorted entraînera un algorithme beaucoup plus rapide. Si vous souhaitez calculer des éléments uniques basés sur une transformation, passez une fonction d’ iterator .

Exemple

 var names = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"]; alert(_.uniq(names, false)); 

Remarque: Lo-Dash (un concurrent de soulignement ) propose également une implémentation .uniq comparable.

Une version à une seule ligne utilisant des fonctions de filtre de tableau et d’indexOf:

 arr = arr.filter (function (value, index, array) { return array.indexOf (value) == index; }); 

Vous pouvez simplement le faire en JavaScript, à l’aide du paramètre deuxième index du filter :

 var a = [2,3,4,5,5,4]; a.filter(function(value, index){ return a.indexOf(value) == index }); 

ou dans la main courte

 a.filter((v,i) => a.indexOf(v) == i) 

Une ligne:

 let names = ['Mike','Matt','Nancy','Adam','Jenny','Nancy','Carl', 'Nancy']; let dup = [...new Set(names)]; console.log(dup); 

Le moyen le plus concis pour supprimer les doublons d’un tableau utilisant les fonctions javascript natives est d’utiliser une séquence comme ci-dessous:

 vals.sort().reduce(function(a, b){ if (b != a[0]) a.unshift(b); return a }, []) 

Il n’y a pas besoin de slice ni d’ indexOf dans la fonction indexOf , comme je l’ai vu dans d’autres exemples! il est logique de l’utiliser avec une fonction de filtre si:

 vals.filter(function(v, i, a){ return i == a.indexOf(v) }) 

Une autre façon de procéder pour ES6 (2015) qui fonctionne déjà sur quelques navigateurs est la suivante:

 Array.from(new Set(vals)) 

ou même en utilisant l’ opérateur de propagation :

 [...new Set(vals)] 

à votre santé!

Allez pour celui-ci:

 var uniqueArray = duplicateArray.filter(function(elem, pos) { return duplicateArray.indexOf(elem) == pos; }); 

Maintenant, uniqueArray ne contient pas de doublons.

Le plus simple que j’ai rencontré jusqu’ici. En es6.

  var names = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl", "Mike", "Nancy"] var noDupe = Array.from(new Set(names)) 

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set

utilisez Array.filter() comme ceci

 var actualArr = ['Apple', 'Apple', 'Banana', 'Mango', 'Strawberry', 'Banana']; console.log('Actual Array: ' + actualArr); var filteredArr = actualArr.filter(function(item, index) { if (actualArr.indexOf(item) == index) return item; }); console.log('Filtered Array: ' + filteredArr); 

J’avais fait une comparaison détaillée de l’enlèvement des dupes à une autre question, mais après avoir remarqué que c’est le vrai lieu, je voulais juste le partager ici aussi.

Je crois que c’est la meilleure façon de le faire

 var myArray = [100, 200, 100, 200, 100, 100, 200, 200, 200, 200], reduced = Object.keys(myArray.reduce((p,c) => (p[c] = true,p),{})); console.log(reduced); 

Ce qui suit est plus de 80% plus rapide que la méthode jQuery listée (voir les tests ci-dessous). C’est une réponse à une question similaire il y a quelques années. Si je rencontre la personne qui l’a initialement proposé, je posterai un crédit. Pure JS.

 var temp = {}; for (var i = 0; i < array.length; i++) temp[array[i]] = true; var r = []; for (var k in temp) r.push(k); return r; 

Ma comparaison de cas de test: http://jsperf.com/remove-duplicate-array-tests

Voici une réponse simple à la question.

 var names = ["Alex","Tony","James","Suzane", "Marie", "Laurence", "Alex", "Suzane", "Marie", "Marie", "James", "Tony", "Alex"]; var uniqueNames = []; for(var i in names){ if(uniqueNames.indexOf(names[i]) === -1){ uniqueNames.push(names[i]); } } 

Dans ECMAScript 6 (aka ECMAScript 2015), Set peut être utilisé pour filtrer les doublons. Ensuite, il peut être reconverti en un tableau à l’aide de l’ opérateur de répartition .

 var names = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"], unique = [...new Set(names)]; 

Une technique simple mais efficace consiste à utiliser la méthode de filter en combinaison avec la function(value, index){ return this.indexOf(value) == index } filtre function(value, index){ return this.indexOf(value) == index } .

Exemple de code:

 var data = [2,3,4,5,5,4]; var filter = function(value, index){ return this.indexOf(value) == index }; var filteredData = data.filter(filter, data ); document.body.innerHTML = '
' + JSON.ssortingngify(filteredData, null, '\t') + '

';

Solution 1

 Array.prototype.unique = function() { var a = []; for (i = 0; i < this.length; i++) { var current = this[i]; if (a.indexOf(current) < 0) a.push(current); } return a; } 

Solution 2 (en utilisant Set)

 Array.prototype.unique = function() { return Array.from(new Set(this)); } 

Tester

 var x=[1,2,3,3,2,1]; x.unique() //[1,2,3] 

Performance

Lorsque j'ai testé les deux implémentations (avec et sans Set) pour les performances en chrome, j'ai trouvé que celle avec Set était beaucoup plus rapide!

 Array.prototype.unique1 = function() { var a = []; for (i = 0; i < this.length; i++) { var current = this[i]; if (a.indexOf(current) < 0) a.push(current); } return a; } Array.prototype.unique2 = function() { return Array.from(new Set(this)); } var x=[]; for(var i=0;i<10000;i++){ x.push("x"+i);x.push("x"+(i+1)); } console.time("unique1"); console.log(x.unique1()); console.timeEnd("unique1"); console.time("unique2"); console.log(x.unique2()); console.timeEnd("unique2"); 

Les réponses les plus fréquentes ont la complexité de O(n²) , mais cela peut être fait avec O(n) en utilisant un object comme hachage:

 function getDistinctArray(arr) { var dups = {}; return arr.filter(function(el) { var hash = el.valueOf(); var isDup = dups[hash]; dups[hash] = true; return !isDup; }); } 

Cela fonctionnera pour les chaînes, les nombres et les dates. Si votre tableau contient des objects complexes (c.-à-d. Qu’ils doivent être comparés à === ), la solution ci-dessus ne fonctionnera pas. Vous pouvez obtenir une implémentation O(n) pour les objects en définissant un indicateur sur l’object lui-même:

 function getDistinctObjArray(arr) { var distinctArr = arr.filter(function(el) { var isDup = el.inArray; el.inArray = true; return !isDup; }); distinctArr.forEach(function(el) { delete el.inArray; }); return distinctArr; } 

here is the simple method without any special libraries are special function,

 name_list = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"]; get_uniq = name_list.filter(function(val,ind) { return name_list.indexOf(val) == ind; }) console.log("Original name list:"+name_list.length, name_list) console.log("\n Unique name list:"+get_uniq.length, get_uniq) 

Apart from being a simpler, more terse solution than the current answers (minus the future-looking ES6 ones), I perf tested this and it was much faster as well:

 var uniqueArray = dupeArray.filter(function(item, i, self){ return self.lastIndexOf(item) == i; }); 

One caveat: Array.lastIndexOf() was added in IE9, so if you need to go lower than that, you’ll need to look elsewhere.

So the options is:

 let a = [11,22,11,22]; let b = [] b = [ ...new Set(a) ]; // b = [11, 22] b = Array.from( new Set(a)) // b = [11, 22] b = a.filter((val,i)=>{ return a.indexOf(val)==i }) // b = [11, 22] 

Generic Functional Approach

Here is a generic and ssortingctly functional approach with ES2015:

 // small, reusable auxiliary functions const apply = f => a => f(a); const flip = f => b => a => f(a) (b); const uncurry = f => (a, b) => f(a) (b); const push = x => xs => (xs.push(x), xs); const foldl = f => acc => xs => xs.reduce(uncurry(f), acc); const some = f => xs => xs.some(apply(f)); // the actual de-duplicate function const uniqueBy = f => foldl( acc => x => some(f(x)) (acc) ? acc : push(x) (acc) ) ([]); // comparators const eq = y => x => x === y; // ssortingng equality case insensitive :D const seqCI = y => x => x.toLowerCase() === y.toLowerCase(); // mock data const xs = [1,2,3,1,2,3,4]; const ys = ["a", "b", "c", "A", "B", "C", "D"]; console.log( uniqueBy(eq) (xs) ); console.log( uniqueBy(seqCI) (ys) ); 
 $(document).ready(function() { var arr1=["dog","dog","fish","cat","cat","fish","apple","orange"] var arr2=["cat","fish","mango","apple"] var uniquevalue=[]; var seconduniquevalue=[]; var finalarray=[]; $.each(arr1,function(key,value){ if($.inArray (value,uniquevalue) === -1) { uniquevalue.push(value) } }); $.each(arr2,function(key,value){ if($.inArray (value,seconduniquevalue) === -1) { seconduniquevalue.push(value) } }); $.each(uniquevalue,function(ikey,ivalue){ $.each(seconduniquevalue,function(ukey,uvalue){ if( ivalue == uvalue) { finalarray.push(ivalue); } }); }); alert(finalarray); }); 

Here is very simple for understanding and working anywhere (even in PhotoshopScript) code. Check it!

 var peoplenames = new Array("Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"); peoplenames = unique(peoplenames); alert(peoplenames); function unique(array){ var len = array.length; for(var i = 0; i < len; i++) for(var j = i + 1; j < len; j++) if(array[j] == array[i]){ array.splice(j,1); j--; len--; } return array; } //*result* peoplenames == ["Mike","Matt","Nancy","Adam","Jenny","Carl"] 
 for (i=0; i 

This is probably one of the fastest way to remove permanently the duplicates from an array 10x times faster than the most functions here.& 78x faster in safari

 function toUnique(a,b,c){ //array,placeholder,placeholder b=a.length;while(c=--b)while(c--)a[b]!==a[c]||a.splice(c,1) } 
  1. Test: http://jsperf.com/wgu
  2. Demo: http://jsfiddle.net/46S7g/
  3. More: https://stackoverflow.com/a/25082874/2450730

if you can’t read the code above ask, read a javascript book or here are some explainations about shorter code. https://stackoverflow.com/a/21353032/2450730

If by any chance you were using

D3.js

You could do

 d3.set(["foo", "bar", "foo", "baz"]).values() ==> ["foo", "bar", "baz"] 

https://github.com/mbostock/d3/wiki/Arrays#set_values

https://jsfiddle.net/2w0k5tz8/

 function remove_duplicates(array_){ var ret_array = new Array(); for (var a = array_.length - 1; a >= 0; a--) { for (var b = array_.length - 1; b >= 0; b--) { if(array_[a] == array_[b] && a != b){ delete array_[b]; } }; if(array_[a] != undefined) ret_array.push(array_[a]); }; return ret_array; } console.log(remove_duplicates(Array(1,1,1,2,2,2,3,3,3))); 

Loop through, remove duplicates, and create a clone array place holder because the array index will not be updated.

Loop backward for better performance ( your loop wont need to keep checking the length of your array)

This was just another solution but different than the rest.

 function diffArray(arr1, arr2) { var newArr = arr1.concat(arr2); newArr.sort(); var finalArr = []; for(var i = 0;i