TypeScript如何创建存储唯一元组/复合键对象的集合?
现有方案的问题
- 基于数组遍历的实现:数据量增大后
has方法是O(n)复杂度,性能会快速下降 - 你考虑的数组作为Map键的方案存在隐藏缺陷:JS/TS的Map对对象类型键是引用匹配,两次传入内容完全相同的数组属于不同的引用,Map会判定为两个不同的键,完全达不到去重效果。
可选最优实现方案
方案1:序列化复合键(适合键可序列化的简单场景)
如果你的复合键元素都是数字、字符串、布尔这类可安全序列化的类型,直接把复合键序列化为字符串作为Set的键即可,实现成本最低,查询性能为O(1)。
class Tuple3Set<T1, T2, T3> { private store = new Set<string>(); // 选择不会出现在键值中的分隔符即可 private readonly SEPARATOR = '|'; add(item: [T1, T2, T3]): void { const key = item.join(this.SEPARATOR); if (this.store.has(key)) { throw new Error(`key already exists: [${item.join(', ')}]`); } this.store.add(key); } has(item: [T1, T2, T3]): boolean { return this.store.has(item.join(this.SEPARATOR)); } } // 使用示例 const set = new Tuple3Set<number, number, number>(); set.add([1,2,3]); // 正常添加 set.add([2,1,3]); // 正常添加 set.add([1,2,3]); // 抛出错误:key already exists
优点:实现简单,内存占用低,性能最优
缺点:仅支持可序列化的键类型,需要注意分隔符不能和键值内容冲突
方案2:多层Map结构(通用方案,支持任意类型键)
如果你的键包含对象、Symbol等无法序列化的类型,或者不想处理序列化冲突问题,可以用多层嵌套Map实现,不需要序列化,查询复杂度为O(k)(k为复合键长度),远优于数组遍历的O(n)。
class CompositeKeySet<T extends any[]> { private root = new Map(); // 唯一标记复合键的终点,避免和键值冲突 private readonly END_FLAG = Symbol('composite_key_end'); add(...keys: T): void { let currentMap = this.root; // 逐层创建嵌套Map for (const key of keys) { if (!currentMap.has(key)) { currentMap.set(key, new Map()); } currentMap = currentMap.get(key); } // 检查键是否已存在 if (currentMap.has(this.END_FLAG)) { throw new Error(`key already exists: [${keys.join(', ')}]`); } currentMap.set(this.END_FLAG, true); } has(...keys: T): boolean { let currentMap = this.root; for (const key of keys) { if (!currentMap.has(key)) return false; currentMap = currentMap.get(key); } return currentMap.has(this.END_FLAG); } } // 使用示例,支持任意长度复合键 const set = new CompositeKeySet<[number, number, number]>(); set.add(1,2,3); // 正常添加 set.add(2,1,3); // 正常添加 set.add(1,2,3); // 抛出错误:key already exists console.log(set.has(1,2,3)); // true
优点:支持任意类型的键(包括引用类型),无序列化冲突问题,性能稳定,可适配任意长度的复合键
缺点:实现复杂度略高于序列化方案,内存占用略高
如果需要存储每个复合键对应的额外属性,只需要把END_FLAG对应的布尔值替换为你要存储的数据即可,相当于直接实现了复合键的Map结构。
内容的提问来源于stack exchange,提问作者user17298649
相关产品推荐
相关产品推荐

