从对象数组中删除重复对象的最佳方法是什么?
来自
var arr =
[
{"name":"Joe", "age":17},
{"name":"Bob", "age":17},
{"name":"Carl", "age": 35},
{"name":"Bob", "age":35},
{"name":"Joe", "age":17},
]
删除重复项后,预期结果为
res= arr =
[
{"name":"Joe", "age":17},
{"name":"Bob", "age":17},
{"name":"Carl", "age": 35},
{"name":"Bob", "age":35},
]
(5个对象,1个副本,4个左侧)。
每个对象的属性数量是固定的,每个数组的属性名称都相同。但是,从数组到数组,它们可能不仅仅是上面的“名称”和“年龄”,但属性的名称可以是任何名称。
@Pointy请将上述问题中的重复单词视为语义上的“重复” - 分别具有相同属性数,相同属性和相同属性值的对象。
答案 0 :(得分:3)
如果对象是否已插入,则可以使用对象进行查找。
编辑:
获取对象的所有属性并使用键值的更新。如果只应该使用一些属性,那么我建议使用带有相关键的数组,比如
['name', 'age']
并将其与
一起使用var key = ['name', 'age'].map(function (k) { return a[k]; }).join('|');
var arr = [{ "name": "Joe", "age": 17 }, { "name": "Bob", "age": 17 }, { "name": "Carl", "age": 35 }, { "name": "Bob", "age": 35 }, { "name": "Joe", "age": 17 }],
filtered = arr.filter(function (a) {
var key = Object.keys(a).map(function (k) { return a[k]; }).join('|');
if (!this[key]) {
return this[key] = true;
}
}, Object.create(null));
console.log(filtered);

答案 1 :(得分:1)
使用Object.keys
,Array.every
和Array.concat
函数的解决方案:
var names = {}, result = [];
arr.forEach(function (v) {
var name = v['name'];
names[name] = names[name] || [];
// considering multiple objects with same 'name' but different 'age' - and vise versa
if (!Object.keys(names[name]).length ||
names[name].every((obj) => ((obj['name'] === name && obj['age'] !== v['age']) || (obj['name'] !== name && obj['age'] === v['age'])) )) {
names[name].push(v);
}
}, names);
Object.keys(names).forEach((k) => result = result.concat(names[k]), result);
console.log(JSON.stringify(result, 0, 4));
输出:
[
{
"name": "Joe",
"age": 17
},
{
"name": "Bob",
"age": 17
},
{
"name": "Bob",
"age": 35
},
{
"name": "Carl",
"age": 35
}
]
答案 2 :(得分:0)
这是从对象数组中过滤任何平面(非嵌套)对象的副本的一般解决方案。不适合这个具体问题。否则,通过根据已知的属性和值建立LUT(例如,由Map对象构成的查找表),可以轻松完成此作业。再次..您可以将此解决方案应用于任何对象数组以删除欺骗。
执行此任务的最佳方式是Object.prototype.compare()的发明所以一旦我们掌握了它,这项工作就变成了游戏。让我们看看吧。
Object.prototype.compare = function(o){
var ok = Object.keys(this);
return typeof o === "object" && ok.length === Object.keys(o).length ? ok.every(k => this[k] === o[k]) : false;
};
var arr =
[
{"name":"Joe", "age":17},
{"name":"Bob", "age":17},
{"name":"Carl", "age": 35},
{"name":"Bob", "age":35},
{"name":"Joe", "age":17},
],
red = arr.reduce((p,c,i) => {var f = p.slice(i).findIndex(o => o.compare(p[i-1]));
return f == -1 ? p : (p.splice(f+i,1),p)},arr);
console.log(JSON.stringify(arr,null,2));

我相信这是迄今为止这样做的最佳方式。我更喜欢Map或Set,但是从这个版本的ES6开始,即使我们可以使用对象作为Map对象中的键,它们仍然无法用于访问值。我的意思是即使关键对象是空对象,另一个空对象也不会定义该关键字。但我认为有一项工作正在进行,因为在Map对象中NaN
可以是一个键,你可以使用NaN
访问它,即使在JS世界中你都知道NaN !== NaN
如;
var m = new Map();
m.set({},true);
m.set("a",1);
m.set(NaN,"cow");
m.get({},true}; // undefined
m.get("a",1); // 1
m.get(NaN,"cow"); // "cow" so NaN == NaN is true in the Map ...
答案 3 :(得分:0)
const arr1 = [{"name":"ren","age":3,"weight":120},{"name":"ren","age":2,"weight":100},{"name":"ren","age":2,"weight":100},{"name":"ren","age":2,"weight":100},{"name":"ren","age":2,"weight":100},{"name":"ren","age":2,"weight":100},{"name":"ren","age":1,"weight":100},{"name":"stimpy","age":2,"weight":100},{"name":"george american","age":56,"weight":220}]
const arr2 = [{"name":"ren","age":2,"weight":150},{"name":"ren","age":2,"weight":150},{"name":"ren","age":2,"weight":150},{"name":"ren","age":2,"weight":100},{"name":"stimpy","age":2,"weight":100},{"name":"ren","age":3,"weight":100},{"name":"stimpy","age":1,"weight":100},{"name":"ren","age":2,"weight":100},{"name":"circus midgets","age":5,"weight":200}]
function uniq_all_props (__arr1, __arr2) {
let arr = __arr1.concat(__arr2)
console.log('arr.length', arr.length)
let set = []
let result = []
arr.forEach(function (__obj) {
/** Set each obj to a string. */
let string = JSON.stringify(__obj)
set.push(string)
})
set.filter(function (elem, index, self) {
/** Use filter as a loop to push onto results array.
* This is done to preserve prop types from original arrays */
if (index === self.indexOf(elem)) {
result.push(arr[index])
}
})
return result
}
console.log(uniq_all_props(arr1, arr2))