我有一组对象
list = [{x:1,y:2}, {x:3,y:4}, {x:5,y:6}, {x:1,y:2}]
我正在寻找一种有效的方法(如果可能的话
O(log(n))
)来删除重复项并最终得到
list = [{x:1,y:2}, {x:3,y:4}, {x:5,y:6}]
我试过
_.uniq
甚至_.contains
但找不到令人满意的解决方案。
谢谢!
编辑:该问题已被确定为与另一个问题重复。我在发布之前看到了这个问题,但它没有回答我的问题,因为它是一个对象数组(而不是 2-dim 数组,谢谢 Aaron),或者至少另一个问题的解决方案在我的案例中不起作用。
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));
尝试使用以下内容:
list = list.filter((elem, index, self) => self.findIndex(
(t) => {return (t.x === elem.x && t.y === elem.y)}) === index)
香草 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));
我会结合使用
Arrayr.prototype.reduce
和 Arrayr.prototype.some
方法与扩展运算符。
1。明确的解决方案。基于对数组对象包含的完整知识。
list = list.reduce((r, i) =>
!r.some(j => i.x === j.x && i.y === j.y) ? [...r, i] : r
, [])
这里我们对比较对象的结构有严格的限制:
{x: N, y: M}
。而[{x:1, y:2}, {x:1, y:2, z:3}]
将被过滤为[{x:1, y:2}]
.
2。通用解决方案,
JSON.stringify()
。比较的对象可以有任意数量的任意属性。
list = list.reduce((r, i) =>
!r.some(j => JSON.stringify(i) === JSON.stringify(j)) ? [...r, i] : r
, [])
这种方法对属性顺序有限制,所以
[{x:1, y:2}, {y:2, x:1}]
不会被过滤。
3。通用解决方案,
Object.keys()
。顺序无关紧要。
list = list.reduce((r, i) =>
!r.some(j => !Object.keys(i).some(k => i[k] !== j[k])) ? [...r, i] : r
, [])
这种方法还有一个局限性:被比较的对象必须有相同的键列表。 因此,尽管存在明显差异,
[{x:1, y:2}, {x:1}]
仍将被过滤。
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
, [])
最后一种方法是通过键的数量、键本身和键值来比较对象。
我创建了一个 Plunker 来玩它。
ES6+的一个内衬
如果你想通过 x 和 y 找到 uniq:
arr.filter((v,i,a)=>a.findIndex(t=>(t.x === v.x && t.y===v.y))===i)
如果你想通过所有属性找到独特的:
arr.filter((v,i,a)=>a.findIndex(t=>(JSON.stringify(t) === JSON.stringify(v)))===i)
以下将起作用:
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 } ]
在检查是否已经在 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>');
没有图书馆,可以在任何深度工作
限制:
string
或 Number
属性作为哈希对象,否则您将得到不一致的结果/**
* 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>
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>
但是,这假定键总是以相同的顺序指定。通过完善迭代器,即使键的顺序不同,我们也可以使解决方案有效。这个问题以及解决方案也适用于涉及
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>
对于 Lodash 4,使用
_.uniqBy
而不是 _.uniq
。
要从对象数组中删除重复项:
// ✅ If you need to check for uniqueness based on a single property
const arr = [
{id: 1, name: 'Tom'},
{id: 1, name: 'Tom'},
{id: 2, name: 'Nick'},
{id: 2, name: 'Nick'},
];
const uniqueIds = [];
const unique = arr.filter(element => {
const isDuplicate = uniqueIds.includes(element.id);
if (!isDuplicate) {
uniqueIds.push(element.id);
return true;
}
return false;
});
// 👇️ [{id: 1, name: 'Tom'}, {id: 2, name: 'Nick'}]
console.log(unique);
// ------------------------------------------------------------
// ------------------------------------------------------------
// ------------------------------------------------------------
// ✅ If you need to check for uniqueness based on multiple properties
const arr2 = [
{id: 1, name: 'Tom'},
{id: 1, name: 'Tom'},
{id: 1, name: 'Alice'},
{id: 2, name: 'Nick'},
{id: 2, name: 'Nick'},
{id: 2, name: 'Bob'},
];
const unique2 = arr2.filter((obj, index) => {
return index === arr2.findIndex(o => obj.id === o.id && obj.name === o.name);
});
// [
// { id: 1, name: 'Tom' },
// { id: 1, name: 'Alice' },
// { id: 2, name: 'Nick' },
// { id: 2, name: 'Bob' }
// ]
console.log(unique2);
使用 lodash 你可以使用这个单线:
_.uniqBy(list, e => { return e.x && e.y })