886 votes

Comment supprimer tous les doublons d'un tableau d'objets ?

J'ai un objet qui contient un tableau d'objets.

obj = {};

obj.arr = new Array();

obj.arr.push({place:"here",name:"stuff"});
obj.arr.push({place:"there",name:"morestuff"});
obj.arr.push({place:"there",name:"morestuff"});

Je me demande quelle est la meilleure méthode pour supprimer les objets en double d'un tableau. Par exemple, obj.arr deviendrait...

{place:"here",name:"stuff"},
{place:"there",name:"morestuff"}

0 votes

Voulez-vous dire comment empêcher qu'une table de hachage/un objet avec tous les mêmes paramètres soit ajouté à un tableau ?

9 votes

Mathew -> S'il est plus simple d'empêcher un objet en double d'être ajouté au tableau en premier lieu, au lieu de le filtrer plus tard, oui, ce serait bien aussi.

18 votes

Je suis toujours surpris de voir comment les gens nomment leurs variables. Parfois, je pense qu'ils veulent vraiment rendre les choses inutilement compliquées. La prochaine étape sera aaaaa.aaaa.push(...) :)

35voto

rturkek Points 77

One liners avec carte ( Haute performance, ne préserve pas l'ordre )

Trouver une solution unique id dans le tableau arr .

const arrUniq = [...new Map(arr.map(v => [v.id, v])).values()]

Si l'ordre est important, consultez la solution avec filtre : Solution avec filtre


Unique par de multiples propriétés ( place y name ) dans le tableau arr

const arrUniq = [...new Map(arr.map(v => [JSON.stringify([v.place,v.name]), v])).values()]

Unique par toutes les propriétés du tableau arr

const arrUniq = [...new Map(arr.map(v => [JSON.stringify(v), v])).values()]

Conserver la première occurrence dans le tableau arr

const arrUniq = [...new Map(arr.slice().reverse().map(v => [v.id, v])).values()].reverse()

30voto

Alex Kobylinski Points 319

Voici une autre option pour le faire en utilisant les méthodes itératives de Array si vous avez besoin de comparer seulement par un champ d'un objet :

    function uniq(a, param){
        return a.filter(function(item, pos, array){
            return array.map(function(mapItem){ return mapItem[param]; }).indexOf(item[param]) === pos;
        })
    }

    uniq(things.thing, 'place');

26voto

Tim Down Points 124501

Il s'agit d'une manière générique de procéder : vous passez une fonction qui teste si deux éléments d'un tableau sont considérés comme égaux. Dans ce cas, elle compare les valeurs de la fonction name y place les propriétés des deux objets comparés.

Réponse ES5

function removeDuplicates(arr, equals) {
    var originalArr = arr.slice(0);
    var i, len, val;
    arr.length = 0;

    for (i = 0, len = originalArr.length; i < len; ++i) {
        val = originalArr[i];
        if (!arr.some(function(item) { return equals(item, val); })) {
            arr.push(val);
        }
    }
}

function thingsEqual(thing1, thing2) {
    return thing1.place === thing2.place
        && thing1.name === thing2.name;
}

var things = [
  {place:"here",name:"stuff"},
  {place:"there",name:"morestuff"},
  {place:"there",name:"morestuff"}
];

removeDuplicates(things, thingsEqual);
console.log(things);

Réponse originale ES3

function arrayContains(arr, val, equals) {
    var i = arr.length;
    while (i--) {
        if ( equals(arr[i], val) ) {
            return true;
        }
    }
    return false;
}

function removeDuplicates(arr, equals) {
    var originalArr = arr.slice(0);
    var i, len, j, val;
    arr.length = 0;

    for (i = 0, len = originalArr.length; i < len; ++i) {
        val = originalArr[i];
        if (!arrayContains(arr, val, equals)) {
            arr.push(val);
        }
    }
}

function thingsEqual(thing1, thing2) {
    return thing1.place === thing2.place
        && thing1.name === thing2.name;
}

removeDuplicates(things.thing, thingsEqual);

1 votes

Deux objets ne seront pas évalués de la même manière, même s'ils partagent les mêmes propriétés et valeurs.

0 votes

Oui, je sais. Mais c'est vrai, je n'ai pas lu la question correctement : Je n'avais pas remarqué que c'était les objets ayant des propriétés identiques qu'il devait éliminer. Je vais modifier ma réponse.

1 votes

Au lieu de while dans arrayContains, utilisez la méthode Array.prototype..some qui renvoie un résultat vrai si l'un des membres du tableau correspond à la condition.

25voto

maccullt Points 1555

Si vous pouvez attendre d'éliminer les doublons après tous les ajouts, l'approche typique consiste à trier d'abord le tableau, puis à éliminer les doublons. Le tri permet d'éviter l'approche N * N qui consiste à balayer le tableau pour chaque élément au fur et à mesure que vous le parcourez.

La fonction "éliminer les doublons" est généralement appelée unique o uniq . Certaines mises en œuvre existantes peuvent combiner les deux étapes, par exemple, uniq du prototype

Ce poste si votre bibliothèque n'en a pas déjà un ! Personnellement, je trouve que c'est le plus simple :

    function unique(a){
        a.sort();
        for(var i = 1; i < a.length; ){
            if(a[i-1] == a[i]){
                a.splice(i, 1);
            } else {
                i++;
            }
        }
        return a;
    }  

    // Provide your own comparison
    function unique(a, compareFunc){
        a.sort( compareFunc );
        for(var i = 1; i < a.length; ){
            if( compareFunc(a[i-1], a[i]) === 0){
                a.splice(i, 1);
            } else {
                i++;
            }
        }
        return a;
    }

0 votes

Cela ne fonctionnera pas pour les objets génériques sans ordre de tri naturel.

0 votes

C'est vrai, j'ai ajouté une version de comparaison fournie par l'utilisateur.

0 votes

Votre version de comparaison fournie par l'utilisateur ne fonctionnera pas car si votre fonction de comparaison est function(_a,_b){return _a.a===_b.a && _a.b===_b.b;} alors le tableau ne sera pas trié.

22voto

doğukan Points 13809

Je pense que la meilleure approche consiste à utiliser réduire le site y Objet de la carte . Il s'agit d'une solution à ligne unique.

const data = [
  {id: 1, name: 'David'},
  {id: 2, name: 'Mark'},
  {id: 2, name: 'Lora'},
  {id: 4, name: 'Tyler'},
  {id: 4, name: 'Donald'},
  {id: 5, name: 'Adrian'},
  {id: 6, name: 'Michael'}
]

const uniqueData = [...data.reduce((map, obj) => map.set(obj.id, obj), new Map()).values()];

console.log(uniqueData)

/*
  in `map.set(obj.id, obj)`

  'obj.id' is key. (don't worry. we'll get only values using the .values() method)
  'obj' is whole object.
*/

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X