JS 集合的的概念与实现
1. 集合的概念
集合是有一组无需担是彼此之间又有一定关系的成员构成,每个成员在集合中只能够出现一次,不同于我们之前说的字典,链表,它是一种包含了不同元素的数据结构。
特点:
- 无序;
- 唯一;
- 和数学上相似:全集、空集、集合相等、子集;
2. 集合的操作方法
- add(ele)
- delete(ele)
- has(ele)
- clear()
- size()
- values()
3. 集合的实现
我们基于一个对象的概念进行如下实现:
class Set {
constructor() {
this._items = {}
this._length = 0
}
add(value) {
if (this.has(value)) return false
this._items[value] = value
this._length += 1
return true
}
remove(value) {
if (this.has(value)) return false
delete this._items[value]
this._length -= 1
return true
}
values() {
return Object.values(this._items)
}
has(value) {
return this._items.hasOwnProperty(value)
}
clear() {
this._items = {}
this._length = 0
}
size(){
return this._length
}
isEmpty(){
return !this._length
}
}
4. 集合运算
集合类别:
- 并集
- 交集
- 差集
- 子集
以下的操作都是依赖上边的集合的类的基本实现
4.1 并集
实现代码
union(otherSet) {
const unionSet = new Set()
this.values().forEach(item => unionSet.add(item))
otherSet.values().forEach(item => unionSet.add(item))
return unionSet
}
调用并打印结果
const setF = new Set()
const setS = new Set()
setF.add(1)
setF.add(2)
setF.add(3)
setS.add(2)
setS.add(3)
setS.add(4)
const otherSet = setF.union(setS)
const res = otherSet.values()
console.log('print result', res) // print result [ 1, 2, 3, 4 ]
4.2 交集
交集的实现思想就是从两个集合中,将相同的元素提取出来放到一个新的集合中
实现代码
intersection(otherSet) {
const intersection = new Set();
const values = this.values();
for (let i = 0; i < values.length; i++) {
if (otherSet.has(values[i])) {
intersection.add(values[i])
}
}
return intersection
}
调用并打印调试结果
const setF = new Set()
const setS = new Set()
setF.add(1)
setF.add(2)
setF.add(3)
setS.add(2)
setS.add(3)
setS.add(4)
const otherSet = setF.intersection(setS)
const res = otherSet.values()
console.log('print result', res) // print result [ 2, 3 ]
4.3 差集
实现思路:同时两个集合,返回一个包含所有存在于第一个集合但是并不存在于第二个集合中的集合
实现代码
difference(otherSet) {
const difference = new Set()
this.values().forEach(item => {
if (!otherSet.has(item)) {
difference.add(item)
}
})
return difference
}
调用并打印调试结果
const setF = new Set()
const setS = new Set()
setF.add(1)
setF.add(2)
setF.add(3)
setS.add(2)
setS.add(3)
setS.add(4)
const otherSet = setF.difference(setS)
const res = otherSet.values()
console.log('print result', res) // print result [ 1 ]
4.4 子集
实现思路:判断一个集合是不是另一个集合的子集
实现代码
isSubsetOf(otherSet) {
if (this.size() > otherSet.size()) {
return false
}
let isSubset = true;
this.values().every(value => {
if (!otherSet.has(value)) {
isSubset = false;
return false
}
return true
})
return isSubset
}
调用并打印调试结果
const setF = new Set()
const setS = new Set()
setF.add(1)
setF.add(2)
setF.add(3)
setS.add(1)
setS.add(2)
setS.add(3)
setS.add(4)
const res = setF.isSubsetOf(setS)
console.log('print result', res) // print result true
5. ES6 Set()
5.1 Set() 方法
- add(ele)
- has(ele)
- delete(ele)
- clear()
5.2 Set()遍历
| 方法 | 说明 |
|---|---|
| Set().prototype.keys() | 返回键名遍历器 |
| Set().prototype.values() | 返回键名遍历器 |
| Set().prototype.entries() | 返回键值对遍历器 |
| Set().prototype.forEach() | 使用回调函数遍历每个成员 |
Set结构没有键名,只有键值,所以keys方法和values方法的行为完全一致
let firstSet = new Set();
firstSet.add(1);
firstSet.add(2);
firstSet.add(3);
firstSet.add('set-key');
let s = { name: 'tom', age: 22 };
firstSet.add(s);
firstSet.add({name: 'tom', age: 22 });
for(let [key, value] of firstSet.entries())
console.log(key, value);
// 查看⼀下打印结果
// 1 1
// 2 2
// 3 3
// set-key set-key
// {name: 'tom', age: 22} {name: 'tom', age: 22}
// {name: 'tom', age: 22} {name: 'tom', age: 22}
6. Set 模拟运算
6.1 并集
function union(setOne, setTwo) {
const newSet = new Set()
setOne.forEach(ele => newSet.add(ele))
setTwo.forEach(ele => {
if (!newSet.has(ele)) {
newSet.add(ele)
}
})
return newSet
}
const unionSet = union(firstSet, secondSet)
console.log('print unionSet', unionSet)
// print unionSet Set(5) { 1, 2, 3, 4, 9 }
6.2 交集
function intersection(setOne, setTwo) {
const newSet = new Set()
setOne.forEach(ele => {
if (setTwo.has(ele)) {
newSet.add(ele)
}
})
return newSet
}
const intersectionSet = intersection(firstSet, secondSet)
console.log('print intersectionSet', intersectionSet)
// print intersectionSet Set(3) { 1, 2, 3 }
6.3 差集
function difference(setOne, setTwo) {
const newSet = new Set()
setOne.forEach(ele => {
if (!setTwo.has(ele)) {
newSet.add(ele)
}
})
return newSet
}
const differenceSet = difference(firstSet, secondSet)
console.log('print differenceSet', differenceSet)
// print differenceSet Set(1) { 4 }
6.4 子集
function isSubsetOf(setOne, setTwo) {
if (setOne.size > setTwo.size) {
return false
}
let isSubset = true
let arr = [...setOne]
arr.every(ele => {
if (!setTwo.has(ele)) {
isSubset = false
return false
}
return true
})
return isSubset
}
const issubset = isSubsetOf(firstSet, thirdSet)
console.log('print issubset', issubset)
// print issubset true