集合 Set
1. Set 特点
集合内部元素唯一, 不允许重复, 支持增删改查的操作。
由于 JavaScript
实现了 ES6
中的 Set
类, 而且 Set
类也比较完善了。所以只需要扩展一下高级功能(并集、差集、交集、补集、子集)就可以愉快地使用了。
2. 注意事项
-
集合的每个元素并不仅仅是一个值, 而是一个键值对, 当运行以下代码时
const s = new Set([1,2,3])
, 并不是单单向集合内插入1,2,3
这 3 个值, 而是以[1,1], [2,2], [3,3]
这种键值对形式保存数据; -
Set
内部判断内部元素是否相同用的是ES6
新增的Object.is
(https://es6.ruanyifeng.com/#docs/object-methods)方法。Object.is
与===
基本一致, 不同点是Object.is
判断时 NaN 与 NaN 是相等的, 并且+0
与-0
不相等; 而===
判断时,NaN
与NaN
不相等,+0
与-0
相等; -
Set 原型对象上已经存在
add delete clear has keys values entries forEach
方法和size
属性, 并可以使用for ... of
去遍历, 以下是简单的示例:
const f = ()=> {console.log(1); return 2}
const s = new Set([`abc`, 123, true, new Date(), /\s/, f])
s.add(f)
console.log(s.has(f))
console.log(s)
s.delete(`abc`)
console.log(s)
// 使用 for ... of 遍历 set
for(let x of s) {
console.log(x)
}
// 使用 for ... of 遍历 set.keys()
for(let k of s.keys()) {
console.log(k)
}
// 使用 for ... of 遍历 set.values()
for(let v of s.values()) {
console.log(v)
}
// 使用 for ... of 遍历 set.entries()
for(let e of s.entries()) {
console.log(e)
}
console.log(s.size)
s.clear()
console.log(s.size)
3. 实现扩展后的 Set
class AdvanceSet extends Set {
/**
* @description 交集 , 返回一个新集合
* @param {...AdvanceSet} sets
* @returns {AdvanceSet | null}
*/
getIntersection(...sets) {
const union = this.getUnion(...sets)
const intersection = new AdvanceSet()
for(let s of union) {
if(sets.every(set=> set.has(s))) {
intersection.add(s)
}
}
return intersection.size > 0 ? intersection : null
}
/**
* @description 并集 , 返回一个新的集合
* @param {...AdvanceSet} sets
* @returns {AdvanceSet}
*/
getUnion(...sets) {
return sets.reduce((prev, cur)=> new AdvanceSet([...prev, ...cur]),this)
}
// 绝对补集 , 返回一个新的集合
/**
* @description 若给定全集U,有A⊆U,则A在U中的相对补集称为A的绝对补集(或简称补集),写作∁UA。
* 注意:学习补集的概念,首先要理解全集的相对性,补集符号∁UA有三层含义:
* 1、A是U的一个子集,即A⊆U;
* 2、∁UA表示一个集合,且∁UA⊆U;
* 3、∁UA是由U中所有不属于A的元素组成的集合,∁UA与A没有公共元素,U中的元素分布在这两个集合中。
* @param {AdvanceSet} universalSet 全集
*/
getComplement(universalSet) {
return new AdvanceSet([...universalSet].filter(element=> !this.has(element)))
}
/**
* 是否是当前集合的补集
* @param {AdvanceSet} universalSet 全集
* @param {AdvanceSet} set 集合
* @returns {Boolean} 以 universalSet 为全集, this 与 set 是否互为补集
*/
isComplement(universalSet, anotherSet) {
const isUniversalIncludesAnotherSet = [...anotherSet].every(element=> universalSet.has(element))
return isUniversalIncludesAnotherSet
? [...this].every(element=> universalSet.has(element) && !anotherSet.has(element))
: false
}
/**
* 当前集合是否为子集
* @param {AdvanceSet} set
* @returns {Boolean}
*/
isSubset(set) {
return [...this].every(s=> set.has(s))
}
/**
* 差集, 又称为相对补集, 返回一个新的集合
* @description 若 A 和 B 是集合,则 A 在 B 中的相对补集是这样一个集合:其元素属于B但不属于A,B - A = { x| x∈B且x∉A}
* @param {AdvanceSet} set
* @returns {AdvanceSet}
*/
getDifferenceSet(set) {
return new AdvanceSet([...this].filter(element=> !set.has(element)))
}
}```
以下是几个简单的测试
```javascript
const a = new AdvanceSet([1, 2, 3, 4])
const b = new AdvanceSet([`a`, `b`, `c`, 4])
const c = new AdvanceSet([{name : 'sk'}, {name : `loa`}, 4])
const d = new AdvanceSet([2, 3, 5])
const e = new AdvanceSet([1, 2, 3, 4, 5, 6, 7])
const f = new AdvanceSet([1, 4, 6, 7])
console.log(a.getUnion(b,c))
console.log(a.getIntersection(b,c))
console.log(d.isSubset(a))
console.log(a.getDifferenceSet(d))
console.log(d.getComplement(e))
console.log(d.isComplement(e,f))