集合(不允许值重复的顺序数据结构)
没有副作用的方法和函数被称为纯函数。纯函数不会修改当前的实例或参数,只会生成一个新的结果。本文实现的 union、intersection 和 difference 方法不会修改当前的 Set 类实例或是作为参数传入的 otherSet。这在函数式编程中是非常重要的概念
class Set {
constructor() {
this.items = {};
}
// 向集合添加一个新元素
add(element) {
if (!this.has(element)) {
this.items[element] = element;
return true;
}
return false;
}
// 从集合移除一个元素
delete(element) {
if (this.has(element)) {
delete this.items[element];
return true;
}
return false;
}
// 如果元素在集合中,返回true,否则返回false
has(element) {
return Object.prototype.hasOwnProperty.call(this.items, element);
}
// 返回一个包含集合中所有值(元素)的数组(高级浏览器)
values() {
// Object.values()方法返回了一个包含给定对象所有属性值的数组
return Object.values(this.items);
}
// 返回一个包含集合中所有值(元素)的数组(所有浏览器)
valuesLegacy() {
let values = [];
for (let key in this.items) {
// {1}
if (this.items.hasOwnProperty(key)) {
values.push(key); // {2}
}
}
return values;
}
// 并集:对于给定的两个集合,返回一个包含两个集合中所有元素的新集合
union(otherSet) {
const unionSet = new Set();
this.values().forEach((value) => unionSet.add(value));
otherSet.values().forEach((value) => unionSet.add(value));
return unionSet;
}
// 交集:对于给定的两个集合,返回一个包含两个集合中共有元素的新集合
intersection(otherSet) {
const intersectionSet = new Set();
const values = this.values();
const otherValues = otherSet.values();
let biggerSet = values;
let smallerSet = otherValues;
// 比较2个集合的大小,小的那个forEach,优化算法使迭代次数最小
if (otherValues.length - values.length > 0) {
biggerSet = otherValues;
smallerSet = values;
}
smallerSet.forEach((value) => {
if (biggerSet.includes(value)) {
intersectionSet.add(value);
}
});
return intersectionSet;
}
// 差集:对于给定的两个集合,返回一个包含所有存在于第一个集合且不存在于第二个集合的元素的新集合
difference(otherSet) {
const differenceSet = new Set();
this.values().forEach((value) => {
if (!otherSet.has(value)) {
differenceSet.add(value);
}
});
return differenceSet;
}
// 子集:验证一个给定集合是否是另一集合的子集
isSubsetOf(otherSet) {
if (this.size() > otherSet.size()) {
return false;
}
let isSubset = true;
this.values().every((value) => {
if (!otherSet.has(value)) {
isSubset = false;
// 配合every,如果回调函数返回false,循环会停止,这就是为什么不用forEach
return false;
}
return true; // 配合every
});
return isSubset;
}
isEmpty() {
return this.size() === 0;
}
// 返回集合中有多少元素
size() {
// Object.keys() 方法会返回一个由一个给定对象的自身可枚举属性组成的数组
return Object.keys(this.items).length;
}
// 返回集合中有多少元素
// 手动提取items对象的每一个属性,记录属性的个数并返回这个数
sizeLegacy() {
let count = 0;
for (let key in this.items) {
if (this.items.hasOwnProperty(key)) {
count++;
}
return count;
}
}
// 移除集合中的所有元素
clear() {
this.items = {};
}
toString() {
if (this.isEmpty()) {
return "";
}
const values = this.values();
let objString = `${values[0]}`;
for (let i = 1; i < values.length; i++) {
objString = `${objString},${values[i].toString()}`;
}
return objString;
}
}
ES2015 Set 类的运算
// 模拟并集运算
const union = (set1, set2) => {
const unionAb = new Set();
set1.forEach((value) => unionAb.add(value));
set2.forEach((value) => unionAb.add(value));
return unionAb;
};
// 模拟交集运算
const intersection = (set1, set2) => {
const intersectionSet = new Set();
set1.forEach((value) => {
if (set2.has(value)) {
intersectionSet.add(value);
}
});
return intersectionSet;
};
// 模拟差集运算
const difference = (set1, set2) => {
const differenceSet = new Set();
set1.forEach((value) => {
if (!set2.has(value)) {
differenceSet.add(value);
}
});
return differenceSet;
};