[英]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),或者至少另一个问题的解决方案在我的案例中不起作用。
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.reduce
和Arrayr.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.对于最后一种方法,对象通过键的数量、键本身和键值进行比较。
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:局限性:
string
or Number
properties as hash objects otherwise you'll get inconsistent results您必须仅提供string
或Number
属性作为 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);
// 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.