用 Set 替代数组查找可将时间复杂度从 O(n) 降至 O(1),关键在于初始化后只读场景及时转换并避免隐式退化回数组操作。

用 Set 替代数组做查找,本质是把 O(n) 降为 O(1);关键不在“怎么转”,而在“什么时候转”和“转完别再退化回数组查”。
数组转 Set:适合初始化后只读查找
如果原始数据是一次性加载、后续主要是判断“是否存在”,就该在初始化阶段转成 Set:
- 用
new Set(arr)构造,不需去重可加Array.from(new Set(arr))再转回(但通常没必要) - 避免边插入边查:比如循环中反复
arr.includes(x),应先const set = new Set(arr),再用set.has(x) - 注意 Set 不保留插入顺序(虽多数引擎保持,但规范不保证),若需顺序+高效查,可搭配 Map 存索引或用 WeakSet(仅限对象)
Set 转数组:仅当必须用数组方法时才转,且尽量缓存
转回数组会丢失查找优势,所以只在必须调用 map、filter、sort 等数组专属方法时才转:
当用户要求为 Java 代码添加注释、修改注释、审查注释、整理注释格式,或要求按照代码注释规范处理 Java 文件时,使用本技能。本技能用于统一生成和维护 Java 类注释模板、按 Git 对比 release 判断版本号、补充每行代码上方中文块注释、调整注释空行规则,并保持 Java 文件 UTF-8 无 BOM 编码。典型触发场景包括:补充类注释、更新 @version、检查 @author 来源、整理行尾注释、把注释放到代码上一行、检查注释是否符合规范、构建前检查 Java 注释风格。
- 优先用 Set 原生方法处理:如
set.forEach、Array.from(set).filter(...)比[...set].filter(...)稍快(少一次展开) - 如果同一 Set 多次转数组,缓存结果:例如
const arr = Array.from(set),后续复用arr,而不是每次[...set] - 避免无谓转换:比如
if ([...set].includes(x))完全等价于set.has(x),却多出构造数组的开销
混合场景:用 Set 管理存在性,用数组管理顺序或结构
真实业务常需兼顾“快速判断”和“有序遍历”,这时不要强求二选一:
立即学习“Java免费学习笔记(深入)”;
- 维护一个 Set 专用于
has查询,另存一份数组用于渲染或排序 —— 写操作时同步更新两者 - 例如:用户列表展示用数组,搜索框实时校验用 Set,添加/删除时同时
push到数组并add到 Set - 内存换时间合理:现代 JS 引擎对小量重复数据(如百级)的内存占用几乎可忽略,但查找性能提升明显
警惕隐式退化:这些写法会让 Set 白转
即使用了 Set,错误用法仍会回到低效路径:
-
Array.from(set).indexOf(x) !== -1→ 直接用set.has(x) -
[...set].some(item => item === x)→ 同样应改用set.has(x) - 把 Set 当数组解构再遍历:
for (const item of [...set]) { ... },改成for (const item of set) { ... }更轻量

















