新的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)的东西?
当前回答
正如上面的答案所提到的,自定义相等性对于可变对象是有问题的。好消息是(我很惊讶还没有人提到这一点)有一个非常流行的库叫做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}]
其他回答
正如上面的答案所提到的,自定义相等性对于可变对象是有问题的。好消息是(我很惊讶还没有人提到这一点)有一个非常流行的库叫做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}]
正如在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方法返回相同的值时,才认为它们相等。
正如其他人所说,目前还没有本地方法可以做到这一点。 但是如果你想用你的自定义比较器来区分一个数组,你可以尝试用reduce方法来做。
function distinct(array, equal) {
// No need to convert it to a Set object since it may give you a wrong signal that the set can work with your objects.
return array.reduce((p, c) => {
p.findIndex((element) => equal(element, c)) > -1 || p.push(c);
return p;
}, []);
}
// You can call this method like below,
const users = distinct(
[
{id: 1, name: "kevin"},
{id: 2, name: "sean"},
{id: 1, name: "jerry"}
],
(a, b) => a.id === b.id
);
...
也许你可以尝试使用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(结果);
为了补充这里的答案,我实现了一个Map包装器,它接受一个自定义哈希函数、一个自定义相等函数,并将具有等效(自定义)哈希值的不同值存储在存储桶中。
可以预见的是,它比czerny的字符串连接方法要慢。
完整源代码在这里:https://github.com/makoConstruct/ValueMap