web-dev-qa-db-fra.com

Supprimer les valeurs en double du tableau JS

J'ai un tableau JavaScript très simple qui peut contenir ou non 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 citer tous les codes que j'ai essayés mais je pense que c'est inutile car ils ne fonctionnent pas. J'accepte aussi les solutions jQuery.

Question similaire:

1175
kramden88

Rapide et sale avec 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);
});
421
Roman Bataev

TL; DR

Utilisation du constructeur Set et de la syntaxe spread :

uniq = [...new Set(array)];

"Smart" mais manière naïve

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

En gros, 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 array:

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 le 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". C’est-à-dire que uniq([1,"1"]) ne renverra que [1]
  • pour la même raison, tous les objets seront considérés comme égaux: uniq([{foo:1},{foo:2}]) ne renverra que [{foo:1}].

Cela dit, si vos tableaux ne contiennent que des primitives et que vous ne vous souciez pas des types (par exemple, ce sont toujours des 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 la recherche linéaire d’objets.

function uniq(a) {
    var prims = {"boolean":{}, "number":{}, "string":{}}, 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);
    });
}

trier | uniq

Une autre option consiste à trier le tableau en premier, 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 objets (car tous les objets sont égaux pour sort). De plus, nous modifions silencieusement le tableau d'origine en tant qu'effet secondaire - ce n'est pas bien! Cependant, si votre entrée est déjà triée, c’est la voie à suivre (il suffit de supprimer sort de ce qui précède).

Unique par ...

Parfois, il est souhaitable de désorganiser une liste en fonction de critères autres que la simple égalité, par exemple, pour filtrer les objets différents, mais partageant 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 ayant des "clés" égales sont supprimés. Étant donné que key devrait 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);
    })
}

Un key() particulièrement utile est JSON.stringify qui supprimera les objets physiquement différents, mais qui "se ressemblent":

a = [[1,2,3], [4,5,6], [1,2,3]]
b = uniqBy(a, JSON.stringify)
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);
    });
}

Dans ES6, vous pouvez utiliser un Set:

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

ou un Map:

function uniqBy(a, key) {
    return [
        ...new Map(
            a.map(x => [key(x), x])
        ).values()
    ]
}

qui fonctionnent également avec des clés non primitives.

Premier ou dernier?

Lorsque vous supprimez des objets à l'aide d'une clé, vous voudrez peut-être conserver le premier des objets "égaux" ou le dernier.

Utilisez la variante Set ci-dessus pour conserver le premier et la Map pour conserver le dernier:

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


function uniqByKeepLast(a, key) {
    return [
        ...new Map(
            a.map(x => [key(x), x])
        ).values()
    ]
}

//

data = [
    {a:1, u:1},
    {a:2, u:2},
    {a:3, u:3},
    {a:4, u:1},
    {a:5, u:2},
    {a:6, u:3},
];

console.log(uniqByKeepFirst(data, it => it.u))
console.log(uniqByKeepLast(data, it => it.u))

Bibliothèques

Les deux méthodes nderscore et Lo-Dash fournissent les 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 existe d’autres avantages intéressants, tels que l’emballage native indexOf, la possibilité d’unifier une clé (iteratee dans leur langage) et des optimisations pour les tableaux déjà triés.

Si vous utilisez jQuery et que vous ne pouvez rien supporter sans un dollar, le résultat est le suivant:

  $.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. Par conséquent, 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:

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 3 ci-dessus, mais un ordre de grandeur plus rapide (à partir de 2017, il est deux fois plus rapide que jamais: les gens essentiels 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('<br>uniq, ms/loop: ' + (new Date() - d)/LOOPS)

var d = new Date();
for(var i = 0; i < LOOPS; i++)
    uniq_fast(a);
document.write('<br>uniq_fast, ms/loop: ' + (new Date() - d)/LOOPS)

ES6

ES6 fournit l'objet Set , ce qui facilite énormément les choses:

function uniq(a) {
   return Array.from(new Set(a));
}

ou

let uniq = a => [...new Set(a)];

Notez que, contrairement à Python, les ensembles ES6 sont itérés dans l'ordre d'insertion. Ce code conserve donc l'ordre du tableau d'origine.

Cependant, si vous avez besoin d'un tableau avec des éléments uniques, pourquoi ne pas utiliser des ensembles dès le début?

Générateurs

Une version "paresseuse" de uniq, basée sur un générateur, peut être construite sur la même base:

  • prendre la valeur suivante de l'argument
  • si cela a déjà été vu, sautez-le
  • sinon, cédez-le et ajoutez-le à l'ensemble des valeurs déjà vues
function* uniqIter(a) {
    let seen = new Set();

    for (let x of a) {
        if (!seen.has(x)) {
            seen.add(x);
            yield x;
        }
    }
}

// example:

function* randomsBelow(limit) {
    while (1)
        yield Math.floor(Math.random() * limit);
}

// note that randomsBelow is endless

count = 20;
limit = 30;

for (let r of uniqIter(randomsBelow(limit))) {
    console.log(r);
    if (--count === 0)
        break
}

// exercise for the reader: what happens if we set `limit` less than `count` and why
3024
georg

J'en ai marre de voir tous les mauvais exemples avec des boucles for-loop ou jQuery. Javascript dispose des outils parfaits pour cela: trier, cartographier et réduire.

Uniq réduire tout en maintenant 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 tri

Il existe probablement des moyens plus rapides, mais celui-ci est plutôt correct.

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 disposez de Sets and Spread, ce qui permet de supprimer facilement 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)
306

Vanilla JS: Supprimer les 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:

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 (commande sûre)

Ou, pour une version sécurisée pour les commandes, utilisez un objet pour stocker toutes les valeurs précédemment vues et vérifiez les valeurs par rapport à celui-ci avant l'ajout à 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: utilise la nouvelle structure de données Set (safe-order)

ECMAScript 6 ajoute la nouvelle structure de données Set, qui permet de stocker des valeurs de tout type. Set.values renvoie les é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"]
96
Casey Kuball

Utilisez nderscore.js

C'est une bibliothèque avec une foule de fonctions pour manipuler des tableaux.

C'est la cravate qui va avec Tux de jQuery et les bretelles de Backbone.js.

_. uniq

_.uniq(array, [isSorted], [iterator]) Alias: unique
Produit une version sans doublon du tableau , en utilisant === pour tester l'égalité des objets. Si vous savez à l'avance que le tableau est trié, passez true pour isSorted exécutera un algorithme beaucoup plus rapide. Si vous souhaitez calculer des éléments uniques en fonction d'une transformation, transmettez une fonction itérateur .

Exemple

var names = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"];

alert(_.uniq(names, false));

Remarque: Lo-Dash (un trait de soulignement concurrent) offre également une implémentation comparable . Uniq .

71
Brandon Boone

Une version à une seule ligne utilisant le filtre de tableau et les fonctions indexOf:

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

Vous pouvez simplement le faire en JavaScript, à l'aide du second paramètre - index - de la méthode filter:

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

ou en bref

a.filter((v,i) => a.indexOf(v) == i)
54
Ashutosh Jha

Une ligne:

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

Le moyen le plus simple de supprimer les doublons d’un tableau à l’aide des fonctions javascript natives consiste à utiliser la séquence suivante:

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

il n'y a pas besoin de slice ni indexOf dans la fonction de réduction, comme je l'ai vu dans d'autres exemples! il est logique de l’utiliser avec une fonction de filtrage:

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

Voici un autre moyen de faire cela qui fonctionne déjà sur quelques navigateurs ES6 (2015):

Array.from(new Set(vals))

ou même en utilisant le spread spread :

[...new Set(vals)]

à votre santé!

34
Ivo

utiliser 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);

cela peut être raccourci dans ES6 pour

actualArr.filter((item,index,self) => self.indexOf(item)==index);

Ici est une bonne explication de Array.filter()

31
Sumit Joshi

Allez pour celui-ci:

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

Maintenant, uniqueArray ne contient aucun doublon.

20
Juhan

Le plus simple que j'ai rencontré jusqu'à présent. 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

19
Deke

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));
}

Test

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

Performance

Lorsque j'ai testé la performance en chrome des deux implémentations (avec et sans Set), j'ai constaté 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");
17
ShAkKiR

J'avais fait une comparaison détaillée de l'enlèvement des dupes à une autre question, mais ayant remarqué que c'était le vrai endroit, 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);

OK .. même si celui-ci est O(n) et les autres sont O (n ^ 2), j'étais curieux de voir une comparaison de référence entre ce tableau de réduction/recherche et le combo filtre/indexOf (j'ai choisi). Jeetendras très belle implémentation https://stackoverflow.com/a/37441144/4543207 ). Je prépare un tableau d’éléments de 100 Ko rempli d’entiers positifs aléatoires de 0 à 9999 et supprime les doublons. Je répète le test 10 fois et la moyenne des résultats montre qu’ils ne concordent pas en performance.

  • Dans firefox v47 réduire & lut: 14.85ms vs filtre et indexOf: 2836ms
  • Dans chrome v51 réduire & lut: 23.90ms par rapport au filtre & indexF: 1066ms

Bien ok jusqu'ici tout va bien. Mais faisons-le correctement cette fois-ci dans le style ES6. Il a l'air tellement cool ..! Mais à partir de maintenant, comment cela va-t-il fonctionner contre la puissante solution de lut est un mystère pour moi. Voyons d’abord le code puis le comparons.

var myArray = [100, 200, 100, 200, 100, 100, 200, 200, 200, 200],
    reduced = [...myArray.reduce((p,c) => p.set(c,true),new Map()).keys()];
console.log(reduced);

Wow c'était court ..! Mais qu'en est-il de la performance? C'est beau ... Depuis le poids du filtre/indexOf levé sur nos épaules, je peux maintenant tester un tableau 1M éléments aléatoires d'entiers positifs dans la plage 0..99999 pour obtenir une moyenne de 10 tests consécutifs. Je peux dire que cette fois c'est un vrai match. Voir le résultat pour vous-même :)

var ranar = [],
     red1 = a => Object.keys(a.reduce((p,c) => (p[c] = true,p),{})),
     red2 = a => reduced = [...a.reduce((p,c) => p.set(c,true),new Map()).keys()],
     avg1 = [],
     avg2 = [],
       ts = 0,
       te = 0,
     res1 = [],
     res2 = [],
     count= 10;
for (var i = 0; i<count; i++){
  ranar = (new Array(1000000).fill(true)).map(e => Math.floor(Math.random()*100000));
  ts = performance.now();
  res1 = red1(ranar);
  te = performance.now();
  avg1.Push(te-ts);
  ts = performance.now();
  res2 = red2(ranar);
  te = performance.now();
  avg2.Push(te-ts);
}

avg1 = avg1.reduce((p,c) => p+c)/count;
avg2 = avg2.reduce((p,c) => p+c)/count;

console.log("reduce & lut took: " + avg1 + "msec");
console.log("map & spread took: " + avg2 + "msec");

Lequel utiliseriez-vous ..? Eh bien pas si vite ...! Ne soyez pas trompé. La carte est en déplacement. Maintenant, regardez ... dans tous les cas ci-dessus, nous remplissons un tableau de taille n avec des nombres compris dans la plage <n. Je veux dire que nous avons un tableau de taille 100 et que nous remplissons de nombres aléatoires de 0 à 9; il y a donc des doublons définis et "presque" définitivement, chaque nombre a un doublon. Et si on remplissait le tableau de taille 100 avec des nombres aléatoires 0..9999. Voyons maintenant Map jouer à la maison. Cette fois, un tableau de 100 000 éléments, mais la plage de nombres aléatoires est compris entre 0 et 1,00 M. Nous ferons 100 tests consécutifs pour faire la moyenne des résultats. OK voyons les paris ..! <- pas de faute de frappe

var ranar = [],
     red1 = a => Object.keys(a.reduce((p,c) => (p[c] = true,p),{})),
     red2 = a => reduced = [...a.reduce((p,c) => p.set(c,true),new Map()).keys()],
     avg1 = [],
     avg2 = [],
       ts = 0,
       te = 0,
     res1 = [],
     res2 = [],
     count= 100;
for (var i = 0; i<count; i++){
  ranar = (new Array(100000).fill(true)).map(e => Math.floor(Math.random()*100000000));
  ts = performance.now();
  res1 = red1(ranar);
  te = performance.now();
  avg1.Push(te-ts);
  ts = performance.now();
  res2 = red2(ranar);
  te = performance.now();
  avg2.Push(te-ts);
}

avg1 = avg1.reduce((p,c) => p+c)/count;
avg2 = avg2.reduce((p,c) => p+c)/count;

console.log("reduce & lut took: " + avg1 + "msec");
console.log("map & spread took: " + avg2 + "msec");

C'est maintenant le retour spectaculaire de Map () ..! Peut-être que maintenant, vous pouvez prendre une meilleure décision lorsque vous souhaitez supprimer les dupes.

Bon ok nous sommes tous heureux maintenant. Mais le rôle principal vient toujours en dernier avec des applaudissements. Je suis sûr que certains d'entre vous se demandent ce que ferait l'objet Set. Maintenant que nous sommes ouverts à ES6 et que nous savons que Map est le vainqueur des jeux précédents, comparons Map avec Set en finale. Un match typique du Real Madrid contre Barcelone cette fois ... ou est-ce? Voyons qui va gagner l'el classico :)

var ranar = [],
     red1 = a => reduced = [...a.reduce((p,c) => p.set(c,true),new Map()).keys()],
     red2 = a => Array.from(new Set(a)),
     avg1 = [],
     avg2 = [],
       ts = 0,
       te = 0,
     res1 = [],
     res2 = [],
     count= 100;
for (var i = 0; i<count; i++){
  ranar = (new Array(100000).fill(true)).map(e => Math.floor(Math.random()*10000000));
  ts = performance.now();
  res1 = red1(ranar);
  te = performance.now();
  avg1.Push(te-ts);
  ts = performance.now();
  res2 = red2(ranar);
  te = performance.now();
  avg2.Push(te-ts);
}

avg1 = avg1.reduce((p,c) => p+c)/count;
avg2 = avg2.reduce((p,c) => p+c)/count;

console.log("map & spread took: " + avg1 + "msec");
console.log("set & A.from took: " + avg2 + "msec");

Wow .. mec ..! De manière inattendue, il ne s’est pas avéré être un el classico du tout. Plus comme le FC Barcelone contre le CA Osasuna :))

17
Redu

Ce qui suit est plus de 80% plus rapide que la méthode jQuery indiquée (voir les tests ci-dessous). C'est une réponse d'une question similaire il y a quelques années. Si je rencontre la personne qui l'avait proposé à l'origine, 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

16
Levi

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 opérateur de propagation .

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

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]);
        }
    }
14
drew7721

Les réponses les plus fréquentes ont la complexité de O(n²), mais vous pouvez le faire avec seulement O(n) en utilisant un objet 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 objets, la solution ci-dessus ne fonctionnera pas car, une fois forcés, ils auront tous la valeur "[object Object]" (ou quelque chose de similaire) et ne peuvent pas être utilisés comme valeur de recherche. Vous pouvez obtenir une implémentation O(n) pour les objets en définissant un indicateur sur l'objet 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;
}

2019 edit: Les versions modernes de JavaScript en font un problème beaucoup plus facile à résoudre. Utiliser Set fonctionnera, que votre tableau contienne des objets, des chaînes, des nombres ou tout autre type.

function getDistinctArray(arr) {
    return [...new Set(arr)];
}

La mise en œuvre est si simple que la définition d’une fonction n’est plus justifiée.

10
gilly3

Une technique simple mais efficace consiste à utiliser la méthode filter en combinaison avec le 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 = '<pre>' + JSON.stringify(filteredData, null, '\t') +  '</pre>';

Voir aussi ce violon .

10
John Slegers

voici la méthode simple sans aucune bibliothèque spéciale sont une fonction spéciale,

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)

enter image description here

9

Donc les options sont:

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]
9
ofir_aghai

En plus d’être une solution plus simple et plus concise que les réponses actuelles (à l’exception des réponses futures de l’ES6), j’ai testé cela et cela a été beaucoup plus rapide:

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

Une mise en garde: Array.lastIndexOf () a été ajouté dans IE9, donc si vous devez aller plus bas que cela, vous devrez chercher ailleurs.

8
csuwldcat

Approche fonctionnelle générique

Voici une approche générique et strictement fonctionnelle avec 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;

// string 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) );

Nous pouvons facilement dériver unique de unqiueBy ou utiliser la mise en oeuvre plus rapide utilisant Sets:

const unqiue = uniqueBy(eq);

// const unique = xs => Array.from(new Set(xs));

Avantages de cette approche:

  • solution générique en utilisant une fonction de comparaison séparée
  • implémentation déclarative et succincte
  • réutilisation d'autres petites fonctions génériques

Considérations de performance

uniqueBy n'est pas aussi rapide qu'une implémentation impérative avec des boucles, mais il est beaucoup plus expressif en raison de sa généricité.

Si vous identifiez uniqueBy comme étant à l'origine d'une dégradation des performances de votre application, remplacez-le par du code optimisé. Autrement dit, écrivez d'abord votre code de manière déclarative et fonctionnelle. Par la suite, si vous rencontrez des problèmes de performances, essayez d’optimiser le code aux emplacements qui sont à l’origine du problème.

Consommation de mémoire et ramassage des ordures

uniqueBy utilise des mutations (Push(x) (acc)) cachées dans son corps. Il réutilise l'accumulateur au lieu de le jeter après chaque itération. Cela réduit la consommation de mémoire et la pression GC. Puisque cet effet secondaire est intégré à la fonction, tout ce qui est à l'extérieur reste pur.

7
user6445533

Voici très simple pour comprendre et travailler n'importe où (même dans PhotoshopScript) du code. Vérifie ça!

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"]
6
bodich
for (i=0; i<originalArray.length; i++) {  
    if (!newArray.includes(originalArray[i])) {
        newArray.Push(originalArray[i]); 
    }
}
5
MBJH

Une légère modification de l'excellente réponse de thg435 pour utiliser un comparateur personnalisé:

function contains(array, obj) {
    for (var i = 0; i < array.length; i++) {
        if (isEqual(array[i], obj)) return true;
    }
    return false;
}
//comparator
function isEqual(obj1, obj2) {
    if (obj1.name == obj2.name) return true;
    return false;
}
function removeDuplicates(ary) {
    var arr = [];
    return ary.filter(function(x) {
        return !contains(arr, x) && arr.Push(x);
    });
}
4
vin_schumi
$(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);
});
4
user3840178

Si par hasard vous utilisiez

D3.js

Vous pourriez faire

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

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

4
jetpackdata.com

C’est probablement l’un des moyens les plus rapides de supprimer définitivement les doublons d’un tableau 10 fois plus vite que la plupart des fonctions présentées ici. & 78x plus rapidement dans un 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/wg
  2. Démo: http://jsfiddle.net/46S7g/
  3. Plus: https://stackoverflow.com/a/25082874/24507

si vous ne pouvez pas lire le code ci-dessus, lisez un livre javascript ou des explications sur un code plus court. https://stackoverflow.com/a/21353032/24507

3
cocco

Bien que la solution ES6 soit la meilleure, je suis déconcertée par le fait que personne n'a montré la solution suivante:

function removeDuplicates(arr){
    o={}
    arr.forEach(function(e){
        o[e]=true
    })
    return Object.keys(o)
}

Ce qu'il faut retenir ici, c'est que les objets DOIVENT avoir des clés uniques. Nous exploitons cela pour supprimer tous les doublons. J'aurais pensé que ce serait la solution la plus rapide (avant ES6).

Gardez à l'esprit que cela trie également le tableau.

3
Sancarn

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)));

Effectuez une boucle, supprimez les doublons et créez un espace réservé de tableau de clonage car l'index du tableau ne sera pas mis à jour.

Boucle en arrière pour de meilleures performances (votre boucle n'aura pas besoin de continuer à vérifier la longueur de votre tableau)

3
THE AMAZING

C'était juste une autre solution mais différente du reste.

function diffArray(arr1, arr2) {
  var newArr = arr1.concat(arr2);
  newArr.sort();
  var finalArr = [];
  for(var i = 0;i<newArr.length;i++) {
   if(!(newArr[i] === newArr[i+1] || newArr[i] === newArr[i-1])) {
     finalArr.Push(newArr[i]);
   } 
  }
  return finalArr;
}
3
Isaac Pak

Pour ceux qui cherchent à aplatir des tableaux avec des éléments en double dans un tableau unique:

function flattenUniq(arrays) {
  var args = Array.prototype.slice.call(arguments);

  var array = [].concat.apply([], args)

  var result = array.reduce(function(prev, curr){
    if (prev.indexOf(curr) < 0) prev.Push(curr);
    return prev;
  },[]);

  return result;
}
2
cjjenkinson

Le moyen le plus simple de supprimer un doublon est de créer une boucle for, de comparer les éléments qui ne sont pas identiques et de les insérer dans le nouveau tableau.

 var array = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"];

 var removeDublicate = function(arr){
 var result = []
 var sort_arr = arr.sort() //=> optional
 for (var i = 0; i < arr.length; i++) {
        if(arr[ i + 1] !== arr[i] ){
            result.Push(arr[i])
        }
 };
  return result
}  
console.log(removeDublicate(array))
==>  ["Adam", "Carl", "Jenny", "Matt", "Mike", "Nancy"]
1
user3449311

Méthode de boucle imbriquée pour supprimer les doublons dans un tableau et préserver l'ordre d'origine des éléments.

var array = [1, 3, 2, 1, [5], 2, [4]]; // INPUT

var element = 0;
var decrement = array.length - 1;
while(element < array.length) {
  while(element < decrement) {
    if (array[element] === array[decrement]) {
      array.splice(decrement, 1);
      decrement--;
    } else {
      decrement--;
    }
  }
  decrement = array.length - 1;
  element++;
}

console.log(array);// [1, 3, 2, [5], [4]]

Explanation: La boucle interne compare le premier élément du tableau à tous les autres éléments en commençant par l'élément dont l'indice est le plus élevé. En décrémentant vers le premier élément, un doublon est séparé du tableau.

Lorsque la boucle interne est terminée, la boucle externe incrémente l'élément suivant à des fins de comparaison et réinitialise la nouvelle longueur du tableau.

1
y2knoproblem

Une autre méthode permettant de faire cela sans écrire beaucoup de code utilise la méthode ES5 Object.keys-:

var arrayWithDuplicates = ['a','b','c','d','a','c'],
    deduper = {};
arrayWithDuplicates.forEach(function (item) {
    deduper[item] = null;
});
var dedupedArray = Object.keys(deduper); // ["a", "b", "c", "d"]

extrait dans une fonction

function removeDuplicates (arr) {
    var deduper = {}
    arr.forEach(function (item) {
        deduper[item] = null;
    });
    return Object.keys(deduper);
}
1
Willem de Wit

Le script suivant renvoie un nouveau tableau contenant uniquement des valeurs uniques. Cela fonctionne sur la chaîne et les nombres. Aucune exigence pour les bibliothèques supplémentaires uniquement Vanilla JS.

Prise en charge du navigateur:

Feature Chrome  Firefox (Gecko)     Internet Explorer   Opera   Safari
Basic support   (Yes)   1.5 (1.8)   9                   (Yes)   (Yes)

https://jsfiddle.net/fzmcgcxv/3/

var duplicates = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl","Mike","Mike","Nancy","Carl"]; 
var unique = duplicates.filter(function(elem, pos) {
    return duplicates.indexOf(elem) == pos;
  }); 
alert(unique);
1
GibboK
function arrayDuplicateRemove(arr){
    var c = 0;
    var tempArray = [];
    console.log(arr);
    arr.sort();
    console.log(arr);
    for (var i = arr.length - 1; i >= 0; i--) {
        if(arr[i] != tempArray[c-1]){
            tempArray.Push(arr[i])
            c++;
        }
    };
    console.log(tempArray);
    tempArray.sort();
    console.log(tempArray);
}
1
M.A.K. Ripon
const numbers = [1, 1, 2, 3, 4, 4];

function unique(array) {
  return array.reduce((a,b) => {
    let isIn = a.find(element => {
        return element === b;
    });
    if(!isIn){
      a.Push(b);
    }
    return a;
  },[]);
}

let ret = unique(numbers); // [1, 2, 3, 4]

le moyen en utilisant réduire et trouver.

1
gnujoow

aLinks est un objet tableau JavaScript simple. Si un élément existe avant les éléments sur lesquels l'index indique qu'un enregistrement en double est supprimé. Je répète pour annuler tous les doublons. Un tableau de passages annule plusieurs enregistrements.

var srt_ = 0;
var pos_ = 0;
do {
    var srt_ = 0;
    for (var i in aLinks) {
        pos_ = aLinks.indexOf(aLinks[i].valueOf(), 0);
        if (pos_ < i) {
            delete aLinks[i];
            srt_++;
        }
    }
} while (srt_ != 0);
0
stanislavs

Rapide et facile avec lodash - var array = ["12346","12347","12348","12349","12349"]; console.log(_.uniqWith(array,_.isEqual));

0
Anand Somani
var lines = ["Mike", "Matt", "Nancy", "Adam", "Jenny", "Nancy", "Carl"];
var uniqueNames = [];

for(var i=0;i<lines.length;i++)
{
    if(uniqueNames.indexOf(lines[i]) == -1)
        uniqueNames.Push(lines[i]);
}
if(uniqueNames.indexOf(uniqueNames[uniqueNames.length-1])!= -1)
    uniqueNames.pop();
for(var i=0;i<uniqueNames.length;i++)
{
    document.write(uniqueNames[i]);
      document.write("<br/>");
}
0
Vishnu
function removeDuplicates(inputArray) {
            var outputArray=new Array();

            if(inputArray.length>0){
                jQuery.each(inputArray, function(index, value) {
                    if(jQuery.inArray(value, outputArray) == -1){
                        outputArray.Push(value);
                    }
                });
            }           
            return outputArray;
        }
0
realmag777
function removeDuplicates (array) {
  var sorted = array.slice().sort()
  var result = []

  sorted.forEach((item, index) => {
    if (sorted[index + 1] !== item) {
      result.Push(item)
    }
  })
  return result
}
0
Matt MacPherson

Solutions Vanilla JS avec une complexité de O(n) (le plus rapide possible pour ce problème). Modifiez la fonction hashFunction pour distinguer les objets (par exemple 1 et "1") si nécessaire. La première solution évite les boucles cachées (communes dans les fonctions fournies par Array).

var dedupe = function(a) 
{
    var hash={},ret=[];
    var hashFunction = function(v) { return ""+v; };
    var collect = function(h)
    {
        if(hash.hasOwnProperty(hashFunction(h)) == false) // O(1)
        {
            hash[hashFunction(h)]=1;
            ret.Push(h); // should be O(1) for Arrays
            return;
        }
    };

    for(var i=0; i<a.length; i++) // this is a loop: O(n)
        collect(a[i]);
    //OR: a.forEach(collect); // this is a loop: O(n)

    return ret;
}

var dedupe = function(a) 
{
    var hash={};
    var isdupe = function(h)
    {
        if(hash.hasOwnProperty(h) == false) // O(1)
        {
            hash[h]=1;
            return true;
        }

        return false;
    };

    return a.filter(isdupe); // this is a loop: O(n)
}
0
cat

Je sais que je suis un peu en retard, mais voici une autre option utilisant jinqJs

voir violon

var result = jinqJs().from(["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"]).distinct().select();
0
NYTom

Le moyen le plus simple de supprimer les doublons de chaîne consiste à utiliser un tableau associatif, puis à parcourir le tableau associatif pour reconstituer la liste/le tableau.

Comme ci-dessous:

var toHash = [];
var toList = [];

// add from ur data list to hash
$(data.pointsToList).each(function(index, Element) {
    toHash[Element.nameTo]= Element.nameTo;
});

// now convert hash to array
// don't forget the "hasownproperty" else u will get random results 
for (var key in toHash)  {
    if (toHash.hasOwnProperty(key)) { 
      toList.Push(toHash[key]);
   }
}

Voilà, les doublons sont partis!

0
nondescript

Si vous ne souhaitez pas inclure une bibliothèque entière, vous pouvez utiliser cette option pour ajouter une méthode utilisable par n'importe quel tableau:

Array.prototype.uniq = function uniq() {
  return this.reduce(function(accum, cur) { 
    if (accum.indexOf(cur) === -1) accum.Push(cur); 
    return accum; 
  }, [] );
}

["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"].uniq()
0
Jonah

Voici une autre approche utilisant jQuery,

function uniqueArray(array){
  if ($.isArray(array)){
    var dupes = {}; var len, i;
    for (i=0,len=array.length;i<len;i++){
      var test = array[i].toString();
      if (dupes[test]) { array.splice(i,1); len--; i--; } else { dupes[test] = true; }
    }
  } 
  else {
    if (window.console) console.log('Not passing an array to uniqueArray, returning whatever you sent it - not filtered!');
      return(array);
  }
  return(array);
}

Auteur: William Skidmore

0
Mathankumar
var duplicates = function(arr){
     var sorted = arr.sort();
   var dup = [];
   for(var i=0; i<sorted.length; i++){
        var rest  = sorted.slice(i+1); //slice the rest of array
       if(rest.indexOf(sorted[i]) > -1){//do indexOf
            if(dup.indexOf(sorted[i]) == -1)    
         dup.Push(sorted[i]);//store it in another arr
      }
   }
   console.log(dup);
}

duplicates(["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"]);
0
neelmeg
var uniqueCompnies = function(companyArray) {
    var arrayUniqueCompnies = [],
        found, x, y;

    for (x = 0; x < companyArray.length; x++) {
        found = undefined;
        for (y = 0; y < arrayUniqueCompnies.length; y++) {
            if (companyArray[x] === arrayUniqueCompnies[y]) {
                found = true;
                break;
            }
        }

        if ( ! found) {
            arrayUniqueCompnies.Push(companyArray[x]);
        }
    }

    return arrayUniqueCompnies;
}

var arr = [
    "Adobe Systems Incorporated",
    "IBX",
    "IBX",
    "BlackRock, Inc.",
    "BlackRock, Inc.",
];
0
shubham kucheria

Cette solution utilise un nouveau tableau et une mappe d'objets à l'intérieur de la fonction. Tout ce qu’il fait est de parcourir le tableau d’origine et d’ajouter chaque entier à la mappe d’objet.

`if (!unique[int])`

intercepte ceci car il existe déjà une propriété de clé sur l'objet portant le même numéro. Ainsi, en sautant ce nombre et en ne permettant pas qu'il soit poussé dans le nouveau tableau.

    function removeRepeats(ints) {
      var unique = {}
      var newInts = []

      for (var i = 0; i < ints.length; i++) {
        var int = ints[i]

        if (!unique[int]) {
          unique[int] = 1
          newInts.Push(int)
        }
      }
      return newInts
    }

    var example = [100, 100, 100, 100, 500]
    console.log(removeRepeats(example)) // prints [100, 500]
0
Dan Zuzevich

Si vous créez vous-même le tableau, vous pouvez économiser une boucle et le filtre unique supplémentaire en effectuant la vérification au moment de l'insertion des données;

var values = [];
$.each(collection, function() {
    var x = $(this).value;
    if (!$.inArray(x, values)) {
        values.Push(x);
    }
});
0