集合
Set 是一种数据结构,用于存储唯一值的集合。它类似于数组,但不允许重复元素。
代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| class mySet { item = {} as { [key: string]: any; };
add(element: any) { if (!this.has(element)) { this.item[element] = element; return true; } return false; }
delete(element: any) { if (this.has(element)) { delete this.item[element]; return true; } return false; }
has(element: any) { return element in this.item; }
clear() { this.item = {}; return true; }
size() { return Reflect.ownKeys(this.item).length; }
values() { return Object.values(this.item); } }
|
ES6 的 Set 结构
-
创建一个新的 Set 对象:可以通过以下任意一种方式创建一个 Set 对象:
1 2
| let set = new Set(); let set = new Set([1, 2, 3]);
|
-
添加元素到集合中:可以使用 add()方法向集合中添加元素:
1 2 3 4
| let set = new Set(); set.add(1); set.add(2); set.add(3);
|
-
删除集合中的元素:可以使用 delete()方法删除集合中的元素:
1 2
| let set = new Set([1, 2, 3]); set.delete(2);
|
-
检查集合中是否存在某个元素:可以使用 has()方法来检查集合中是否存在某个元素:
1 2 3
| let set = new Set([1, 2, 3]); set.has(2); set.has(4);
|
-
获取集合的大小:可以使用 size 属性获取集合中元素的数量:
1 2
| let set = new Set([1, 2, 3]); set.size;
|
-
迭代集合中的元素:可以使用 for…of 循环或者 forEach()方法来迭代 Set 中的所有元素:
1 2 3 4 5 6 7 8
| let set = new Set([1, 2, 3]); for (let item of set) { console.log(item); }
set.forEach(function (value) { console.log(value); });
|
利用 set 取并集, 交集, 差集
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| const setA = new Set([1, 2, 3, 4, 5]); const setB = new Set([3, 4, 5, 6, 7]);
const c = new Set([...setA, ...setB]); console.log(c);
const d = new Set([...setA].filter(item => setB.has(item))); console.log(d);
const e = new Set([...setA].filter(item => !setB.has(item))); console.log(e);
|
字典
字典和集合很类似, 集合以(值, 值)的形式存储数据, 字典则以(键, 值)
的形式存储数据, 字典也成为映射, 符号表, 或关联数组
ES6 中的 Set
和 Map
都是集合(collection)类型,但它们有一些区别:
-
Set
是一组有序且唯一的值的集合,而 Map
是一组键值对(key-value)的集合。
-
在 Set
中,每个元素只出现一次,可以用来去重;在 Map
中,每个键(key
)只能对应一个值(value
),但同一个值可以被多个键所对应。
-
Set
采用类似数组的方式来访问其成员,而 Map 则采用键来访问其成员。
-
Set
的主要方法包括 add
、delete
、has
、clear
等,而 Map
的主要方法包括 set
、get
、has
、delete
、clear
等。
因此,如果需要存储一组唯一的值或进行去重操作,可以使用 Set
;如果需要存储键值对,并且需要通过键来访问其对应的值,则可以使用 Map
。
代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| class Dictionary { table = {} as { [k: string]: any; }; toStr(item: any) { if (item === null) return "null"; if (item === undefined) return "undefined"; if (typeof item === "string" || item instanceof String) return item as string; return JSON.stringify(item); }
set(key: any, value: any) { if (key !== null && value !== null) { this.table[this.toStr(key)] = new keyPair(key, value); return true; } return false; } get(key: any) { const value = this.table[this.toStr(key)]?.value; if (value) { return value; } return undefined; } hasKey(key: any) { return this.table[this.toStr(key)] != null; } keys() { return this.keyValues().map(item => item.key); } values() { return this.keyValues().map(item => item.value); } keyValues() { return Object.values(this.table); } size() { return Object.keys(this.table).length; } isEmpty() { return this.size() === 0; } clear() { this.table = {}; } foreach(cb: Function) { const pair = this.keyValues(); for (let i = 0; i < this.size(); i++) { cb(pair[i].key, pair[i].value); } } } class keyPair { key: any; value: any; constructor(key: any, value: any) { this.key = key; this.value = value; } }
const dir = new Dictionary();
|
hashMap 散列表
散列表将 key 通过一个散列函数转化为固定长度, 解决了字典结构如果 key 过长会造成查找时间过长的问题
散列表的代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| import { keyPair } from "./map";
class hashMap { table = {} as { [k: string]: any; }; toStr(item: any) { if (item === null) return "null"; if (item === undefined) return "undefined"; if (typeof item === "string" || item instanceof String) return item as string; return JSON.stringify(item); } hashCode(key: any) { if (typeof key === "number") { return key; } const tableKey = this.toStr(key); let hash = 5381; [...tableKey].forEach(item => { hash = hash * 33 + item.charCodeAt(0); }); return hash % 1013; } set(key: any, value: any) { if (key && value) { const position = this.hashCode(key); this.table[position] = new keyPair(key, value); return true; } return false; } get(key: any) { return this.table[this.hashCode(key)]; } remove(key: any) { const hash = this.hashCode(key); if (this.table[hash]) { delete this.table[hash]; return true; } return false; } }
|
ES6 的 Map
ES6 中的 Map 结构可以用来存储键值对,其使用方法如下:
-
创建一个空的 Map 对象
1
| const myMap = new Map();
|
-
添加键值对到 Map 中
-
从 Map 中获取某个键对应的值
1
| const value = myMap.get(key);
|
-
检查 Map 中是否存在指定的键
1
| const hasKey = myMap.has(key);
|
-
获取 Map 中所有的键或值
1 2
| const keys = myMap.keys(); const values = myMap.values();
|
-
获取 Map 中键值对的数量
1
| const size = myMap.size;
|
-
遍历 Map 中的所有键值对
1 2 3
| myMap.forEach((value, key) => { });
|
需要注意的是,Map 中的键可以是任何类型的值,而不仅限于字符串和数字。此外,Map 也提供了其他一些有用的方法,比如删除特定键的值,清空 Map 等。
WeakMap 和 WeakSet
WeakMap 和 WeakSet 是 ES6 中新增的两种集合类型,它们都具有以下特点:
-
只能存储对象作为键,不能使用原始值类型(如字符串、数字等)作为键。
-
对于存储在集合中的对象,当没有其他对象引用它们时,它们会被自动回收。
其中,WeakMap 是一种以弱引用方式存储键值对的类似 Map 的数据结构。与 Map 不同的是,WeakMap 中的键只能是对象,而且这些对象都是弱引用的。也就是说,当某个对象作为 WeakMap 的键时,如果没有其他对象引用该键所对应的对象,则这个键值对会被自动从 WeakMap 中删除,以释放其占用的内存。
以下是一个使用 WeakMap 的示例:
1 2 3 4 5 6 7 8 9 10 11
| const myWeakMap = new WeakMap();
const key = {};
myWeakMap.set(key, "value");
console.log(myWeakMap.get(key));
key = null;
|
另一方面,WeakSet 是一种以弱引用方式存储对象的类似 Set 的数据结构。与 Set 不同的是,WeakSet 中的元素只能是对象,而且这些对象都是弱引用的。也就是说,当某个对象作为 WeakSet 的元素时,如果没有其他对象引用该元素,则这个元素会被自动从 WeakSet 中删除,以释放其占用的内存。
以下是一个使用 WeakSet 的示例:
1 2 3 4 5 6 7 8 9 10 11 12 13
| const myWeakSet = new WeakSet();
const obj1 = {}; const obj2 = {};
myWeakSet.add(obj1); myWeakSet.add(obj2);
console.log(myWeakSet.has(obj1));
obj1 = null;
|