集合-基本实现
集合是由一组无序且唯一(即不能重复)的项组成的一种结构.
该数据结构使用了与有限集合相同的数学概念.
基于的操作基本围绕并集, 交集, 差集等展开. 多的就不讲了, 基本的数学常识还是具备的. 我用集合用得比较多的地方就是在做一些数据统计, 数据拆分等会用到.
创建集合
这里我们底层用 js 对象来实现, 用对象有个好处是它的键天然就是要求唯一的, 比较好操作. 当然用数组也行, 只是操作没有那么方便, 但也能搞.
class Set {
constructor() {
// 这里用对象来实现集合, key 唯一比较方便
this.obj = {}
}
集合方法
- add(element):向集合添加一个新元素
- delete(element):从集合移除一个元素
- has(element):如果元素在集合中,返回true,否则返回false。
- clear():移除集合中的所有元素。
- size():返回集合所包含元素的数量。它与数组的length属性类似。
- values():返回一个包含集合中所有值(元素)的数组。
元素是否在集合中
底层是用对象来存储元素, 直接用 in
运算符即可, 但更推荐用 hasOwnProperty()
方法.
- in : 属性会查找实例本身 +
原型链
- hasOwnProperty() : 仅限于实例本身
has(element) {
return Object.prototype.hasOwnProperty.call(this.obj, element)
}
这里不直接用 obj.hasOwnProperty(key)
的原因是并非所有对象都集成了 Object.prototype
. 直接用可能导致异常, 所以才用原型链 + call 改变 this 指向 的方式来稳一手.
添加元素
要先判断元素是否已在集合中, 不在才能添加, 再就返回 false 啦.
add(element) {
if (! this.has(element)) {
this.obj[element] = element
return true
}
return false
}
删除元素
- 删除一项
- 删除全部
delete(element) {
if (this.has(element)) {
// 底层是对象, 可以直接用 delete
delete this.obj[element]
return true
}
return false
}
clear() {
this.obj = {}
}
集合大小
- 定义一个
length
变量, 每次 add, delete 时进行控制 - ES6: Object.keys(obj).length
- 对象属性遍历
// 方法3实现
size() {
let count = 0
for (let key in this.obj) {
if (this.obj.hasOwnProperty(key)) count++
}
return count
}
集合元素列表
- ES6: Object.values(obj) 返回对象值组成的数组
- 对象属性遍历
values() {
let arr = []
for (let key in this.obj) {
if (this.obj.hasOwnProperty(key)) {
arr.push(key)
}
}
return arr
}
完整实现
class Set {
constructor() {
// 这里用对象来实现集合, key 唯一比较方便, 当然也可以用数组
this.obj = {}
}
// 查询元素是否在集合中
has(element) {
// return element in this.obj
return Object.prototype.hasOwnProperty.call(this.obj, element)
}
// 添加元素
add(element) {
if (! this.has(element)) {
this.obj[element] = element
return true
}
return false
}
// 删除元素
delete(element) {
if (this.has(element)) {
// 能用 delete 是因为底层用的是对象
delete this.obj[element]
return true
}
return false
}
// 清空集合
clear() {
this.obj = {}
}
// 集合元素个数
size() {
// 方法1: 使用一个 count 变量, 每次新增/删除时进行控制
// 方法2: 用 ES6 语法, Object.keys().length 返回键组成的数组
// return Object.keys(this.obj).length
// 方法3: 手动提取底层对象的属性进行计数
let count = 0
for (let key in this.obj) {
// in 会包含原型链上的, hasOwnProperty() 只查找实例自身的
if (this.obj.hasOwnProperty(key)) count++
}
return count
}
// 返回集合元素值
values() {
// 方法1: 用 ES6, Object.values() 返回值组成的数组
// return Object.values(this.obj)
// 方法2: 遍历对象 key 都存起来
let arr = []
for (let key in this.obj) {
if (this.obj.hasOwnProperty(key)) arr.push(key)
}
return arr
}
}
测试:
const set = new Set();
set.add(1);
console.log(set.values()); // 输出[1]
console.log(set.has(1)); // 输出true
console.log(set.size()); // 输出1
set.add(2);
console.log(set.values()); // 输出[1, 2]
console.log(set.has(2)); // 输出true
console.log(set.size()); // 输出2
set.delete(1);
console.log(set.values()); // 输出[2]
set.delete(2);
console.log(set.values()); // 输出[]
关于集合的基本实现思路就到这里啦.
耐心和恒心, 总会获得回报的.