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.
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));
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));
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)
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.
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>');
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 } ]