集合是一种不允许值重复的顺序数据结构。
通过集合我们可以进行并集、交集、差集等数学运算, 还会更深入的理解如何使用 ECMAScript 2015(ES2015)原生的 Set 类。
构建数据集合
集合是由一组无序且唯一
(即不能重复)的项组成的。该数据结构使用了与有限集合相同的数学概念,但应用在计算机科学的数据结构中。
在数学中的概念
集合,简称集,是数学中一个基本概念,也是集合论的主要研究对象。
集合是指具有某种特定性质的具体的或抽象的对象汇总而成的集体。其中,构成集合的这些对象则称为该集合的元素;
基数
集合中元素的数目称为集合的基数,集合A的基数记作card(A)。当其为有限大时,集合A称为有限集,反之则为无限集 [4] 。一般的,把含有有限个元素的集合叫做有限集,含无限个元素的集合叫做无限集 [4] 。
表示
假设有实数x < y:
①[x,y] :方括号表示包括边界,即表示x到y之间的数以及x和y;
②(x,y):小括号是不包括边界,即表示大于x、小于y的数 [4] 。
特性
-
确定性:给定一个集合,任给一个元素,该元素或者属于或者不属于该集合,二者必居其一,不允许有模棱两可的情况出现 [6] 。
-
互异性:一个集合中,任何两个元素都认为是不相同的,即每个元素只能出现一次。有时需要对同一元素出现多次的情形进行刻画,可以使用多重集,其中的元素允许出现多次 [6] 。
-
无序性:一个集合中,每个元素的地位都是相同的,元素之间是无序的。集合上可以定义序关系,定义了序关系后,元素之间就可以按照序关系排序。但就集合本身的特性而言,元素之间没有必然的序 [6] 。
创建集合类
class Set{
constructor(){
this.items = {}
}
}
实现常用的方法:(尝试模拟与 ECMAScript 2015 实现相同的 Set 类)
add(element):向集合添加一个新元素。
delete(element):从集合移除一个元素。
has(element):如果元素在集合中,返回 true,否则返回 false。 clear():移除集合中的所有元素。
size():返回集合所包含元素的数量。它与数组的 length 属性类似。 values():返回一个包含集合中所有值(元素)的数组。
实现has(element)
//第一种方式
has(element){
return element in items;
};
//第二种
has(element) {
return Object.prototype.hasOwnProperty.call(this.items, element);
}
说明:也可以在代码中使用 this.items.hasOwnProperty(element)。但是, 如果这样的话,代码检查工具如 ESLint 会抛出一个错误。错误的原因为不是所 有的对象都继承了 Object.prototype,甚至继承了 Object.prototype 的对 象上的 hasOwnProperty 方法也有可能被覆盖,导致代码不能正常工作。要避 免出现任何问题,使用 Object.prototype.hasOwnProperty.call 是更安全的做法。
add方法
add(element) {
if (!this.has(element)) {
this.items[element] = element; // {1}
return true;
}
return false;
}
说明:添加一个 element 的时候,把它同时作为键和值保存,因为这样有利于查找该 元素。
其他方法这里不再一一实现。
集合的运算
集合是数学中基础的概念,在计算机领域也非常重要。它在计算机科学中的主要应用之一是 数据库,而数据库是大多数应用程序的根基。集合被用于查询的设计和处理。当我们创建一条从 关系型数据库(Oracle、Microsoft SQL Server、MySQL 等)中获取一个数据集合的查询语句时, 使用的就是集合运算,并且数据库也会返回一个数据集合。当我们创建一条 SQL 查询命令时, 可以指定是从表中获取全部数据还是获取其中的子集;也可以获取两张表共有的数据、只存在于 9 一张表中的数据(不存在于另一张表中),或是存在于两张表内的数据(通过其他运算)。这些
SQL 领域的运算叫作联接,而 SQL 联接的基础就是集合运算。
计算包括:这里不再逐一实现,只详细介绍子集:
并集:对于给定的两个集合,返回一个包含两个集合中所有元素的新集合。
交集:对于给定的两个集合,返回一个包含两个集合中共有元素的新集合。
差集:对于给定的两个集合,返回一个包含所有存在于第一个集合且不存在于第二个集合的元素的新集合。
子集:验证一个给定集合是否是另一集合的子集。
isSubsetOf(otherSet) {
if (this.size() > otherSet.size()) { // {1}
return false;
}
let isSubset = true; // {2}
this.values().every(value => { // {3}
if (!otherSet.has(value)) { // {4}
isSubset = false; // {5}
return false;
}
return true; // {6}
});
return isSubset; // {7}
}
说明:在 isSubsetOf 方法中,我们不会像在并集、交集和差集中一样使用 forEach 方法。我们 会用 every 方法代替,它也是 ES2015 中的数组方法,只要回调函数返回 true,every 方法就会被调用(行{6})。如果 回调函数返回 false,循环会停止,这就是为什么我们要在行{5}改变 isSubset 标识的值。
ECMAScript 2015——Set 类
和上面实现的 Set 不同,ES2015 的 Set 的 values 方法返回 Iterator,而不 是值构成的数组。另一个区别是,我们实现的 size 方法返回 set 中存储的值的个数,而 ES2015 的 Set 则有一个 size 属性。
ES6 提供了新的数据接结构Set(集合)。它类似于数组,但成员的值都是唯一的,集合实现了iterator接口,所以可以使用【扩展运算符】和【for…of】进行遍历,集合的属性和方法:
- size 返回集合的元素个数
2)add 增加一个新元素,返回当前集合 - delete 删除元素,返回boolean值
- has 检测集合中是否包含某个元素,返回boolean值
5)clear 清空集合,返回undefined
- size
//声明一个set
let s=new Set();
let s2=new Set(['大事儿','小事儿','好事儿','坏事儿','小事儿']);//接收可迭代数据
//元素个数
console.log(s2.size);//输出4
- add
s2.add('喜事儿');
console.log(s2);
- delete
//删除元素
s2.delete('坏事儿');
- has
console.log(s2.has('糟心事'));// 输出false
- clear
s2.clear();
console.log(s2);
- 遍历
for(let v of v2){
console.log(v);
}
ES2015 Set 类的运算
上面的 Set 类实现了并集、交集、差集、子集等数学运算,然而 ES2015 原生的 Set 并没有 这些功能。只能模拟实现。
这里只实现一个,余下可以感兴趣的可以自己动手实现。
模拟实现交集:
const intersection = (setA, setB) => {
const intersectionSet = new Set();
setA.forEach(value => {
if (setB.has(value)) {
intersectionSet.add(value);
}
});
return intersectionSet;
};
console.log(intersection(setA, setB)); // 输出[2, 3]
关于扩展运算符…
有一种计算并集、交集和差集的简便方法,就是使用扩展运算符