JS不可重复集合MySet
Set介绍
ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。添加使用add()方法,长度为size属性,判断包含元素用has()方法,遍历可使用for of 或者 forEach()方法。
Set添加对象
但是Set集合的元素,如果添加多个对象,则除非是同一个对象,才可以去重。如果添加多个对象,但是对象中的属性和值都相同,由于Set是采用 === 比较对象的,所以多个相同属性和值的对象,是可以添加进去的。
扩展Set,支持对象去重
由于笔者项目中,有遇到需要对对象集合进行去重的需要,所以自定义了MySet,继承自Set,重写了add、has方法,使其支持添加对象时,自动去重。
原理:利用一个对象,key来记录已经添加的对象计算出的唯一值,来确保添加对象时,重复的唯一值的对象不再添加。
MySet实现
MySet继承自Set,主要是重写了add()方法、has()、delete()方法,可以传入一个方法,用来计算添加或比较的对象的唯一值,该值作为对象的唯一标记。
/**
* 自定义Set,支持添加对象去重(指定对象值方法)
*/
class MySet extends Set {
constructor(params, valFnc) {
super();
this.valObject = {};
if (params) {
// 构造函数传入集合,调用add方法初始化
for (let item of params) {
this.add(item, valFnc);
}
}
}
add(val, valFnc) {
if (valFnc) {
// 该对象计算出的值存在,则返回,不添加
if (this.valObject[valFnc(val)]) {
return;
}
// 标记存在
this.valObject[valFnc(val)] = true;
}
super.add(val);
}
has(val, valFnc) {
if (valFnc) {
return this.valObject[valFnc(val)] ? true : false;
}
return super.has(val);
}
delete(val, valFnc) {
if (valFnc) {
let del = null;
for (let item of this) {
if (valFnc(val) === valFnc(item)) {
this.valObject[valFnc(val)] = false;
del = item;
break;
}
}
return super.delete(del);;
} else {
return super.delete(val);
}
}
clear() {
this.valObject = {};
super.clear();
}
}
MySet使用
由于继承了Set对象,所以完全可以像使用Set一样来使用MySet
let mySet = new MySet();
// MySet元素值获取方法
let valFnc = (v) => v.name;
mySet.add({name: "张三"}, valFnc);
mySet.add({name: "李四"}, valFnc);
mySet.add({name: "张三"}, valFnc);
mySet.add({name: "王五"}, valFnc);
console.log(mySet.size); // 3
console.log(mySet.has({name: "张三"}, valFnc)); // true
console.log(mySet.delete({name: "张三"}, valFnc)) // true
console.log(mySet.size); // 3
console.log(mySet);
let array = [{
name: "a"
}, {
name: "b"
}, {
name: "c"
}, {
name: "b"
}];
let s1 = new MySet(array);
console.log(s1.size); // 4
let s2 = new MySet(array, valFnc);
console.log(s2.size); // 3
console.log(s2.has({name: "a"}, valFnc)); // true