简体   繁体   English

删除 object 数组中的重复项 Javascript

[英]Remove duplicates in an object array Javascript

I have an array of objects我有一个对象数组

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

And I'm looking for an efficient way (if possible O(log(n)) ) to remove duplicates and to end up with我正在寻找一种有效的方法(如果可能的话O(log(n)) )来删除重复项并最终得到

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

I've tried _.uniq or even _.contains but couldn't find a satisfying solution.我试过_.uniq甚至_.contains但找不到令人满意的解决方案。

Thanks!谢谢!

Edit: The question has been identified as a duplicate of another one.编辑:该问题已被确定为与另一个问题重复。 I saw this question before posting but it didn't answer my question since it's an array of object (and not a 2-dim array, thanks Aaron), or at least the solutions on the other question weren't working in my case.我在发布之前看到了这个问题,但它没有回答我的问题,因为它是 object 的数组(而不是 2-dim 数组,谢谢 Aaron),或者至少另一个问题的解决方案在我的案例中不起作用。

Plain javascript (ES2015), using Set纯 javascript (ES2015),使用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));

Try using the following:尝试使用以下方法:

list = list.filter((elem, index, self) => self.findIndex(
    (t) => {return (t.x === elem.x && t.y === elem.y)}) === index)

Vanilla JS version:香草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 = [cx, cy].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));

I would use a combination of Arrayr.prototype.reduce and Arrayr.prototype.some methods with spread operator.我会使用Arrayr.prototype.reduceArrayr.prototype.some方法与扩展运算符的组合。

1. Explicit solution . 1. 明确的解决方案 Based on complete knowledge of the array object contains.基于数组对象包含的完整知识。

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

Here we have strict limitation on compared objects structure: {x: N, y: M} .这里我们对比较对象结构有严格的限制: {x: N, y: M} And [{x:1, y:2}, {x:1, y:2, z:3}] will be filtered to [{x:1, y:2}] .[{x:1, y:2}, {x:1, y:2, z:3}]将被过滤为[{x:1, y:2}]

2. Generic solution, JSON.stringify() . 2. 通用解决方案, JSON.stringify() The compared objects could have any number of any properties.比较对象可以具有任意数量的任何属性。

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

This approach has a limitation on properties order, so [{x:1, y:2}, {y:2, x:1}] won't be filtered.这种方法对属性顺序有限制,因此[{x:1, y:2}, {y:2, x:1}]不会被过滤。

3. Generic solution, Object.keys() . 3. 通用解决方案, Object.keys() The order doesn't matter.顺序无关紧要。

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

This approach has another limitation: compared objects must have the same list of keys.这种方法还有另一个限制:比较对象必须具有相同的键列表。 So [{x:1, y:2}, {x:1}] would be filtered despite the obvious difference.所以[{x:1, y:2}, {x:1}]会被过滤掉,尽管有明显的区别。

4. Generic solution, Object.keys() + .length . 4. 通用解决方案, 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
, [])

With the last approach objects are being compared by the number of keys, by keys itself and by key values.对于最后一种方法,对象通过键的数量、键本身和键值进行比较。

I created a Plunker to play with it.我创建了一个Plunker来玩它。

The following will work:以下将起作用:

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 } ]

Filter the array after checking if already in a temorary object in O(n).在检查是否已经在 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 = ax + '|' + ay; if (!o[k]) { o[k] = true; return true; } }); }(list); document.write('<pre>' + JSON.stringify(filtered, 0, 4) + '</pre>');

One liners for ES6+一个 ES6+ 的衬垫

If you want to find uniq by x and y:如果你想通过 x 和 y 找到 uniq:

arr.filter((v,i,a)=>a.findIndex(t=>(t.x === v.x && t.y===v.y))===i)

If you want to find uniques by all properties:如果要按所有属性查找唯一值:

arr.filter((v,i,a)=>a.findIndex(t=>(JSON.stringify(t) === JSON.stringify(v)))===i)

No libraries, and works with any depth没有图书馆,可以在任何深度工作

Limitation:局限性:

  • You must provide only string or Number properties as hash objects otherwise you'll get inconsistent results您必须仅提供stringNumber属性作为 hash 对象,否则您会得到不一致的结果
/** 
 * Implementation, you can convert this function to the prototype pattern to allow
 * usage like `myArray.unique(...)`
 */ 
function unique(array, f) {
  return Object.values(
    array.reduce((acc, item) => ({ ...acc, [f(item).join(``)]: item }), {})
  );
}

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

// Usage
const result = unique(list, item => [item.x, item.y]);

// Output: [{ x: 1, y: 2}, {x: 3, y: 4}, { x: 5, y: 6}]
console.log(result); 

Snippet Sample片段样本

 // Implementation function unique(array, f) { return Object.values( array.reduce((acc, item) => ({...acc, [f(item).join(``)]: item }), {}) ); } // Your object list const list = [{ x: 1, y: 2}, {x: 3, y: 4}, { x: 5, y: 6}, { x: 1, y: 2}]; // Usage const result = unique(list, item => [item.x, item.y]); // Add result to DOM document.querySelector(`p`).textContent = JSON.stringify(result, null, 2);
 <p></p>

With Underscore's _.uniq and the standard JSON.stringify it is a oneliner:使用 Underscore 的_.uniq和标准JSON.stringify它是一个单行代码:

 var list = [{x:1,y:2}, {x:3,y:4}, {x:5,y:6}, {x:1,y:2}]; var deduped = _.uniq(list, JSON.stringify); console.log(deduped);
 <script src="https://underscorejs.org/underscore-umd-min.js"></script>

However, this presumes that the keys are always specified in the same order.但是,这假定键总是以相同的顺序指定。 By sophisticating the iteratee, we can make the solution work even if the order of the keys varies.通过完善迭代器,即使键的顺序不同,我们也可以使解决方案有效。 This problem as well as the solution also apply to other answers that involve JSON.stringify .这个问题以及解决方案也适用于涉及JSON.stringify的其他答案。

 var list = [{x:1,y:2}, {x:3,y:4}, {x:5,y:6}, {y:2, x:1}]; // Ensure that objects are always stringified // with the keys in alphabetical order. function replacer(key, value) { if (._;isObject(value)) return value. var sortedKeys = _.keys(value);sort(). return _,pick(value; sortedKeys). } // Create a modified JSON.stringify that always // uses the above replacer. var stringify = _.partial(JSON,stringify, _, replacer; null). var deduped = _,uniq(list; stringify). console;log(deduped);
 <script src="https://underscorejs.org/underscore-umd-min.js"></script>

For Lodash 4, use _.uniqBy instead of _.uniq .对于 Lodash 4,使用_.uniqBy而不是_.uniq

使用 lodash 你可以使用这个单行:

 _.uniqBy(list, e => { return e.x && e.y })

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM