使用Typescript实现集合的操作

2,740 阅读5分钟

数学中的集合

定义

所谓的一个集合,就是将数个对象归类而分成为一个或数个形态各异的大小整体。 一般来讲,集合是具有某种特性的事物的整体,或是一些确认对象的汇集。构成集合的事物或对象称作**[元素]** 或是 成员。集合的元素可以是任何事物,可以是人,可以是物,也可以是字母或数字等

符号

元素通常都是小写, 比如 a,b,c,d,xa,b,c,d,x; 集合通常都是大写, 比如: A,B,C,D,XA,B,C,D,X

  1. 空集: \empty空集是任何集合的子集
  2. 属于与不属于(元素和集合之间): ,\in, \notin; 元素aa属于集合AA,则 表示 aAa \in A; 元素aa不属于集合AA,则 表示 aAa \notin A
  3. 包含与被包含(集合之间): ,,,\subset, \subseteq, \supset, \supseteq
  4. 交集: AB\bigcap, A \bigcap B
  5. 并集: AB\bigcup, A \bigcup B
  6. 真子集: ABABA \subseteq B 且 A \not= B 则 A 是 B的真子集

集合的特性

1. 无序性

一个集合中,每个元素的地位都是相同的,元素之间是无序的。

2. 互异性

一个集合中,任何两个元素都认为是不相同的,即每个元素只能出现一次。

3. 确定性

给定一个集合,任给一个元素,该元素或者属于或者不属于该集合,二者必居其一,不允许有模棱两可的情况出现。

集合运算

1. 并集

两个集合可以相"加", A 和 B的并集,就是将A 和 B的元素放在一起构成一个新的集合; 即 AB={eeAeB}A\bigcup B = \{ e|e \in A 或 e \in B \} image.png 示例: A=1,2,3;B=3,4,5;AB={1,2,3,4,5}(同样满足集合的特性)A = {1, 2, 3}; B = {3, 4, 5}; A \bigcup B = \{ 1, 2, 3, 4, 5 \} (同样满足 集合的特性)

2. 交集

一个新的集合也可以通过两个集合有的元素来构造;即 AB={eeAeB}A\bigcap B = \{ e|e \in A 且 e \in B\}

image.png 示例: A={1,2,3};B={3,4,5};AB={3}A = \{1, 2, 3\}; B = \{3, 4, 5\}; A \bigcap B = \{3\}

3.差集

两个集合也可以相"减", A - B, 则 构成的集合 属于A 但是 不属于B; AB={eeAeB}A - B = \{e | e \in A 且 e \notin B\} AA=A - A = \empty

image.png 示例: A={1,2,3};B={3,4,5};AB={1,2}A = \{1, 2, 3\}; B = \{3, 4, 5\}; A - B = \{1, 2\}

4.对称差

两个集合的对称差是只属于其中一个集合,而不属于另一个集合的元素组成的集合 AB=(AB)(BA)=(AB)(AB)A \vartriangle B = (A - B) \bigcup (B - A) = (A \bigcup B) - (A \bigcap B)

image.png 示例: A={1,2,3};B={3,4,5};AB={1,2,4,5}A = \{1, 2, 3\}; B = \{3, 4, 5\}; A \vartriangle B = \{ 1, 2, 4, 5 \}

Set 对象

Set对象是值的集合,你可以按照插入的顺序迭代它的元素。 Set中的元素只会出现一次,即 Set 中的元素是唯一的。

实例方法

    const set: Set<any> = new Set([1, 2, 3, 4]);

1. Set.prototype.add(value)

在Set对象尾部添加一个元素 , 如果Set对象中包含了 该元素, 则不会添加;

const set: Set<any> = new Set([1, 2, 3, 4]);
set.add(5)
console.log(set) // Set(5) { 1, 2, 3, 4, 5 }
set.add(1) // 因为 set里已经有1 这个元素了, 则不会添加
console.log(set) // Set(5) { 1, 2, 3, 4, 5 }

2. Set.prototype.clear()

移除Set对象内的所有元素。

const set: Set<any> = new Set([1, 2, 3, 4]);
set.clear()
console.log(set) // Set(0) {}

3. Set.prototype.delete(value)

移除Set中与这个值相等的元素,返回Set.prototype.has(value)在这个操作前会返回的值(即如果该元素存在,返回true,否则返回false)。Set.prototype.has(value)在此后会返回false; 可以理解成,是否删除成功

const set: Set<any> = new Set([1, 2, 3, 4]);
console.log(set.delete(1)) // true
console.log(set.delete(10)) // false

4. Set.prototype.entries()

返回一个新的迭代器对象,该对象包含Set对象中的按插入顺序排列的所有元素的值的[value, value]数组

const set: Set<any> = new Set([1, 2, 3, 4]);
console.log(set.entries()) // [Set Entries] { [ 1, 1 ], [ 2, 2 ], [ 3, 3 ], [ 4, 4 ] }

5. Set.prototype.forEach(callback, context)

按照插入顺序,为Set对象中的每一个值调用一次callBackFn。如果提供了context参数,回调中的this会是这个参数。

const set: Set<any> = new Set([1, 2, 3, 4]);
set.forEach(function(key: any, value: any, set:Set<any> ){
 console.log(value0, value1, set)
})
/***
1 1 Set(4) { 1, 2, 3, 4 } 
2 2 Set(4) { 1, 2, 3, 4 }
3 3 Set(4) { 1, 2, 3, 4 }
4 4 Set(4) { 1, 2, 3, 4 }
***/

如果context传入值, 则 this指向该参数; 否则 默认的this 在 node环境: undefined 浏览器环境: window

const set: Set<any> = new Set([1, 2, 3, 4]);
set.forEach(function(this: any, key: any, value: any, set: Set<any>){
  console.log(key, value, set, this)
}, {
  author: '请叫我张先森'
})
/***
1 1 Set(4) { 1, 2, 3, 4 } { author: '请叫我张先森' }
2 2 Set(4) { 1, 2, 3, 4 } { author: '请叫我张先森' }
3 3 Set(4) { 1, 2, 3, 4 } { author: '请叫我张先森' }
4 4 Set(4) { 1, 2, 3, 4 } { author: '请叫我张先森' }
***/

6. Set.prototype.has(value)

返回一个布尔值,表示该值在Set中存在与否。

const set: Set<any> = new Set([1, 2, 3, 4]);
console.log(set.has(1)) // true
console.log(set.has(10)) // false

7. Set.prototype.keys()

返回一个新的迭代器对象,该对象包含Set对象中的按插入顺序排列的所有元素的值。

const set: Set<any> = new Set([1, 2, 3, 4]);
console.log(set.keys()) // [Set Iterator] { 1, 2, 3, 4 }

8. Set.prototype.values()

Set.prototype.keys()一样, 返回一个新的迭代器对象,该对象包含Set对象中的按插入顺序排列的所有元素的值。

const set: Set<any> = new Set([1, 2, 3, 4]);
console.log(set.keys()) // [Set Iterator] { 1, 2, 3, 4 }

实现简易的数学集合操作

class CustomSet<T>  {
  private set: Set<T> ;
  constructor (set?: Iterable<T> | null | undefined) {
    this.set = new Set(set)
  }

  // 添加值
  add (value: T) {
    this.set.add(value)
  }

  // 判断值是否在
  has(value: T):boolean {
    return this.set.has(value)
  }

  // 删除值
  delete (value: T): boolean {
    return this.set.delete(value)
  }

  // 清除所有值
  clear () {
    this.set.clear()
  }

  // 返回[value, value]迭代器对象
  entries(): IterableIterator<[T, T]> {
    return this.set.entries()
  }

  // forEach方法
  forEach(callback: (value: T, value2: T, set: Set<T>) => any, context: any = this) {
    this.set.forEach(callback, context)
  }

  // 获取 所有元素值
  keys ():IterableIterator<T>{
    return this.set.keys()
  }

  // 获取 所有元素值
  values ():IterableIterator<T>{
    return this.set.keys()
  }

  // 差集
  diff (set: CustomSet<any>): CustomSet<any> {
    const _set: CustomSet<any> = new CustomSet<any>(this.set)
    set.forEach(function(value: any) {
      if (_set.has(value)) {
        _set.delete(value)
      }
    })
    return _set
  }

  // 并集
  union (set: CustomSet<any>): CustomSet<any> {
    const _set: CustomSet<any> = new CustomSet<any>(
      [...this.values(), ...set.values()]
    )
    return _set
  }

  // 交集
  intersection (set: CustomSet<any>): CustomSet<any> {
    const _set: CustomSet<any> = new CustomSet<any>()
    set.forEach((value: any) =>  {
      if (this.has(value)) {
        _set.add(value)
      }
    })
    return _set
  }
  // 对称差
  symmetricDiff (set: CustomSet<any>): CustomSet<any> {
    const unions = this.union(set)
    const diff = this.intersection(set)
    const _set = unions.diff(diff)
    return _set
  }

}

测试:

const a = new CustomSet([1, 2, 3, 4 ,5])
const b = new CustomSet([2, 3, 4, 5, 6])
console.log(a.diff(b))  // CustomSet { set: Set(1) { 1 } }
console.log(a.union(b)) // CustomSet { set: Set(6) { 1, 2, 3, 4, 5, 6 } }
console.log(a.intersection(b)) // CustomSet { set: Set(4) { 2, 3, 4, 5 } }
console.log(a.symmetricDiff(b)) // CustomSet { set: Set(2) { 1, 6 } }