新的ES 6 (Harmony)引入了新的Set对象。Set使用的恒等算法类似于===运算符,所以不太适合比较对象:
var set = new Set();
set.add({a:1});
set.add({a:1});
console.log([...set.values()]); // Array [ Object, Object ]
如何自定义相等的集合对象,以做深度对象比较?有没有类似Java = (Object)的东西?
新的ES 6 (Harmony)引入了新的Set对象。Set使用的恒等算法类似于===运算符,所以不太适合比较对象:
var set = new Set();
set.add({a:1});
set.add({a:1});
console.log([...set.values()]); // Array [ Object, Object ]
如何自定义相等的集合对象,以做深度对象比较?有没有类似Java = (Object)的东西?
当前回答
正如在jfriend00的回答中提到的,平等关系的定制可能是不可能的。
下面的代码给出了一个计算效率高(但内存消耗大)的解决方案:
class GeneralSet {
constructor() {
this.map = new Map();
this[Symbol.iterator] = this.values;
}
add(item) {
this.map.set(item.toIdString(), item);
}
values() {
return this.map.values();
}
delete(item) {
return this.map.delete(item.toIdString());
}
// ...
}
每个插入的元素都必须实现返回字符串的toIdString()方法。当且仅当两个对象的toIdString方法返回相同的值时,才认为它们相等。
其他回答
也许你可以尝试使用JSON.stringify()来进行深度对象比较。
例如:
Const arr = [ {名称:“a”,值:10}, {名称:“a”,值:20}, {名称:“a”,值:20}, {名称:“b”,价值:30}, {名称:“b”,价值:40}, {名称:“b”,价值:40} ]; const names = new Set(); Const result = arr。name .has(JSON.stringify(item)) ?names.add(JSON.stringify(item)): false); console.log(结果);
正如上面的答案所提到的,自定义相等性对于可变对象是有问题的。好消息是(我很惊讶还没有人提到这一点)有一个非常流行的库叫做immutable-js,它提供了一组丰富的不可变类型,这些类型提供了您正在寻找的深层值相等语义。
下面是你使用immutable-js的例子:
const { Map, Set } = require('immutable');
var set = new Set();
set = set.add(Map({a:1}));
set = set.add(Map({a:1}));
console.log([...set.values()]); // [Map {"a" => 1}]
正如其他人所说,当前版本的Set没有办法做到这一点。 我的建议是使用数组和映射的组合。
下面的代码将基于您自己定义的键创建唯一键的映射,然后将唯一项的映射转换为一个数组。
Const数组= [ {"name": "Joe", "age": 17}, {"name": "Bob", "age": 17}, {"name": "Carl", "age": 35} ] Const key = 'age'; const arrayUniqueByKey =[…]新地图(数组。地图(项= > (项目(关键),项目))). values ()]; console.log (arrayUniqueByKey); / *输出 [ {"name": "Bob", "age": 17}, {"name": "Carl", "age": 35} ] * / //注意:这将选择列表中最后一个重复的项。
正如在jfriend00的回答中提到的,平等关系的定制可能是不可能的。
下面的代码给出了一个计算效率高(但内存消耗大)的解决方案:
class GeneralSet {
constructor() {
this.map = new Map();
this[Symbol.iterator] = this.values;
}
add(item) {
this.map.set(item.toIdString(), item);
}
values() {
return this.map.values();
}
delete(item) {
return this.map.delete(item.toIdString());
}
// ...
}
每个插入的元素都必须实现返回字符串的toIdString()方法。当且仅当两个对象的toIdString方法返回相同的值时,才认为它们相等。
直接比较它们似乎是不可能的,但是JSON。如果键刚刚排序,Stringify就可以工作。正如我在评论中指出的那样
JSON。stringify({a:1, b:2}) !== JSON。stringify ({2,: 1});
但我们可以用自定义stringify方法来解决这个问题。首先,我们编写方法
函数定义把
Object.prototype.stringifySorted = function(){
let oldObj = this;
let obj = (oldObj.length || oldObj.length === 0) ? [] : {};
for (let key of Object.keys(this).sort((a, b) => a.localeCompare(b))) {
let type = typeof (oldObj[key])
if (type === 'object') {
obj[key] = oldObj[key].stringifySorted();
} else {
obj[key] = oldObj[key];
}
}
return JSON.stringify(obj);
}
一组
现在我们使用Set。但是我们使用的是字符串集合而不是对象
let set = new Set()
set.add({a:1, b:2}.stringifySorted());
set.has({b:2, a:1}.stringifySorted());
// returns true
获取所有的值
在创建集合并添加值之后,我们可以通过
let iterator = set.values();
let done = false;
while (!done) {
let val = iterator.next();
if (!done) {
console.log(val.value);
}
done = val.done;
}
这里有一个链接,所有这些都在一个文件中 http://tpcg.io/FnJg2i