集合通常是由一组无序的、不能重复的元素构成。集合可以看成是一种特殊的数组,特殊之处在于里面的元素没有顺序,也不能重复,没有顺序意味着不能通过下标值访问,不能重复意味着相同的相同的对象在集合中只会存在一份。
集合比较常见的实现方式是哈希表。
2011年6月发布的 ES5 中已经包含了 Array 类。
2015年6月发布的 ES6 中包含了 Set 类。所以其实可以不封装,直接使用。
集合的实现:
// 封装集合
function Set() {
// 使用一个对象来保存集合中的元素,因为 Object 的 keys 本身就是一个集合
this.items = {}
}
// 集合中的操作
// 向集合中添加一个新的值
Set.prototype.add = function(value) {
// 判断当前集合中是否已经包含了该元素
if (this.has(value)) return false
this.items[value] = value
return true
}
// 从集合中移除一个值
Set.prototype.remove = function(value) {
// 判断当前集合中是否已经包含了该元素
if (!this.has(value)) return false
delete this.items[value]
return true
}
// 如果值在集合中,返回 true,否则返回 false
Set.prototype.has = function(value) {
return this.items.hasOwnProperty(value)
}
// 移除集合中的所有值
Set.prototype.clear = function() {
this.items = {}
}
// 返回集合所包含的的值数量
Set.prototype.size = function() {
return Object.keys(this.items).length
}
// 返回一个包含集合中所有值的数组
Set.prototype.values = function() {
return Object.keys(this.items)
}
// 调用集合
var s = new Set()
s.add('Mary')
s.add('Tom')
s.add('Bob')
s.add('Mary')
console.log(s.values()) // ['Mary', 'Tom', 'Bob']
s.remove('Mary')
s.remove('Mary')
console.log(s.values()) // ['Tom', 'Bob']
s.clear()
console.log(s.size()) // 0
集合之间的操作:
并集:
并集:对于给定的两个集合,返回一个包含两个集合中所有值的新集合。
// 并集
Set.prototype.union = function(otherSet) {
// 1. 创建一个新的集合
var unionSet = new Set()
// 2. 将源集合中的所有值添加到新集合中
var values = this.values()
values.forEach(v => unionSet.add(v))
// 3. 取出目标集合中的值添加到新集合中
// 因此 add() 方法中已经有做值是否存在的判断,因此此处不再需要额外判断了
var otherValues = otherSet.values()
otherValues.forEach(v => unionSet.add(v))
return unionSet
}
// 测试并集
var s = new Set()
s.add('Mary')
s.add('Tom')
s.add('Bob')
console.log(s.values()) // ['Mary', 'Tom', 'Bob']
var otherS = new Set()
otherS.add('Mary')
otherS.add('Lee')
otherS.add('John')
console.log(s.values()) // ['Mary', 'Lee', 'John']
var unionSet = s.union(otherS)
console.log(unionSet.values()) // ['Mary', 'Tom', 'Bob', 'Lee', 'John']
交集:
交集:对于给定的两个集合,返回一个包含两个集合中共有值的新集合。
// 交集
Set.prototype.intersection = function(otherSet) {
// 1. 创建一个新的集合
var intersectionSet = new Set()
// 2. 取出源集合中的所有值,进行遍历,判断每个值是否存在于目标集合中,如果存在的话则添加到新集合中
var values = this.values()
values.forEach(v => {
if (otherSet.has(v)) {
intersectionSet.add(v)
}
})
return intersectionSet
}
// 测试并集
var s = new Set()
s.add('Mary')
s.add('Tom')
s.add('Bob')
console.log(s.values()) // ['Mary', 'Tom', 'Bob']
var otherS = new Set()
otherS.add('Mary')
otherS.add('Lee')
otherS.add('John')
console.log(s.values()) // ['Mary', 'Lee', 'John']
var intersectionSet = s.intersection(otherS)
console.log(intersectionSet.values()) // ['Mary']
差集:
差集:对于给定的两个集合,返回一个包含所有存在于第一个集合且不存在于第二个集合的值的新集合。
// 差集
Set.prototype.difference = function(otherSet) {
// 1. 创建一个新的集合
var differenceSet = new Set()
// 2. 取出源集合中的所有值,进行遍历,判断每个值是否不存在于目标集合中,如果不存在的话则添加到新集合中
var values = this.values()
values.forEach(v => {
if (!otherSet.has(v)) {
differenceSet.add(v)
}
})
return differenceSet
}
// 测试差集
var s = new Set()
s.add('Mary')
s.add('Tom')
s.add('Bob')
console.log(s.values()) // ['Mary', 'Tom', 'Bob']
var otherS = new Set()
otherS.add('Mary')
otherS.add('Lee')
otherS.add('John')
console.log(s.values()) // ['Mary', 'Lee', 'John']
var differenceSet = s.difference(otherS)
console.log(differenceSet.values()) // ['Tom', 'Bob']
子集:
子集:验证一个给定集合的所有值是否完全存在于另一个集合中。
// 子集
Set.prototype.sub = function(otherSet) {
// 1. 创建一个新的集合
var subSet = new Set()
// 2. 取出源集合中的所有值,进行遍历;如果源集合中的某个值不存在于目标集合中,返回 false;如果遍历完源集合中的所有值,都没有不存在于目标集合中的值,那么返回 true
var values = this.values()
for(var i = 0; i < values.length; i++) {
console.log(1)
if (!otherSet.has(values[i])) {
return false
}
}
return true
}
// 测试子集
var s = new Set()
s.add('Mary')
s.add('Tom')
s.add('Bob')
console.log(s.values()) // ['Mary', 'Tom', 'Bob']
var otherS = new Set()
otherS.add('Mary')
otherS.add('Lee')
otherS.add('John')
console.log(s.values()) // ['Mary', 'Lee', 'John']
console.log(s.sub(otherS)) // false