web-dev-qa-db-fra.com

Supprimer les doublons dans un tableau d'objets Javascript

J'ai un tableau d'objets

list = [{x:1,y:2}, {x:3,y:4}, {x:5,y:6}, {x:1,y:2}]

Et je cherche un moyen efficace (si possible O(log(n))) pour supprimer les doublons et se retrouver avec

list = [{x:1,y:2}, {x:3,y:4}, {x:5,y:6}]

J'ai essayé _.uniq Ou même _.contains Mais je n'ai pas trouvé de solution satisfaisante.

Merci!

Modifier: la question a été identifiée comme un doublon d'une autre. J'ai vu cette question avant de poster, mais elle n'a pas répondu à ma question car c'est un tableau d'objets (et non un tableau à 2 dim, merci Aaron), ou du moins les solutions sur l'autre question ne fonctionnaient pas dans mon cas.

20
kwn

Version Vanilla JS:

const list = [{x:1,y:2}, {x:3,y:4}, {x:5,y:6}, {x:1,y:2}];

function dedupe(arr) {
  return arr.reduce(function(p, c) {

    // create an identifying id from the object values
    var id = [c.x, c.y].join('|');

    // if the id is not found in the temp array
    // add the object to the output array
    // and add the key to the temp array
    if (p.temp.indexOf(id) === -1) {
      p.out.Push(c);
      p.temp.Push(id);
    }
    return p;

    // return the deduped array
  }, {
    temp: [],
    out: []
  }).out;
}

console.log(dedupe(list));
13
Andy

Javascript simple (ES2015), en utilisant Set

const list = [{ x: 1, y: 2 }, { x: 3, y: 4 }, { x: 5, y: 6 }, { x: 1, y: 2 }];

const uniq = new Set(list.map(e => JSON.stringify(e)));

const res = Array.from(uniq).map(e => JSON.parse(e));

document.write(JSON.stringify(res));
22
isvforall

Essayez d'utiliser les éléments suivants:

list = list.filter((elem, index, self) => self.findIndex(
    (t) => {return (t.x === elem.x && t.y === elem.y)}) === index)
16
Lava kumar N R

J'utiliserais une combinaison de méthodes Arrayr.prototype.reduce Et Arrayr.prototype.some Avec l'opérateur d'étalement.

1. Solution explicite . Basé sur une connaissance complète de l'objet tableau contient.

list = list.reduce((r, i) => 
  !r.some(j => i.x === j.x && i.y === j.y) ? [...r, i] : r
, [])

Ici, nous avons une limitation stricte sur la structure des objets comparés: {x: N, y: M}. Et [{x:1, y:2}, {x:1, y:2, z:3}] Sera filtré en [{x:1, y:2}].

2. Solution générique, JSON.stringify(). Les objets comparés peuvent avoir n'importe quel nombre de propriétés.

list = list.reduce((r, i) => 
  !r.some(j => JSON.stringify(i) === JSON.stringify(j)) ? [...r, i] : r
, [])

Cette approche a une limitation sur l'ordre des propriétés, donc [{x:1, y:2}, {y:2, x:1}] Ne sera pas filtré.

3. Solution générique, Object.keys(). L'ordre n'a pas d'importance.

list = list.reduce((r, i) => 
  !r.some(j => !Object.keys(i).some(k => i[k] !== j[k])) ? [...r, i] : r
, [])

Cette approche a une autre limitation: les objets comparés doivent avoir la même liste de clés. Ainsi [{x:1, y:2}, {x:1}] Serait filtré malgré la différence évidente.

4. Solution générique, Object.keys() + .length.

list = list.reduce((r, i) => 
  !r.some(j => Object.keys(i).length === Object.keys(j).length 
    && !Object.keys(i).some(k => i[k] !== j[k])) ? [...r, i] : r
, [])

Avec la dernière approche, les objets sont comparés par le nombre de clés, par les clés elles-mêmes et par les valeurs des clés.

J'ai créé un Plunker pour jouer avec.

6
dhilt

Filtrez le tableau après avoir vérifié s'il se trouve déjà dans un objet temporaire dans O (n).

var list = [{ x: 1, y: 2 }, { x: 3, y: 4 }, { x: 5, y: 6 }, { x: 1, y: 2 }],
    filtered = function (array) {
        var o = {};
        return array.filter(function (a) {
            var k = a.x + '|' + a.y;
            if (!o[k]) {
                o[k] = true;
                return true;
            }
        });
    }(list);

document.write('<pre>' + JSON.stringify(filtered, 0, 4) + '</pre>');
4
Nina Scholz

Les éléments suivants fonctionneront:

var a = [{x:1,y:2}, {x:3,y:4}, {x:5,y:6}, {x:1,y:2}];

var b = _.uniq(a, function(v) { 
    return v.x && v.y;
})

console.log(b);  // [ { x: 1, y: 2 }, { x: 3, y: 4 }, { x: 5, y: 6 } ]
1
chris p bacon