JavaScript中如何从嵌套数组中删除指定的子数组?
我有如下数组:
arr = [ [1, 2], [2, 3], [3, 4] ]
我想要删除其中的[2, 3]项,最终得到的结果如下:
arr = [ [1, 2], [3, 4] ]
我已经参考了相关删除数组指定元素的方案,但都没有生效,想请问有没有高效快速的实现方式?
补充说明
我已经尝试过使用indexOf和findIndex方法,但是这两个方法都无法返回嵌套数组内子数组的索引值:
arr = [ [1, 2], [2, 3], [3, 4] ]; console.log(arr.indexOf([2, 3])); console.log(arr.findIndex([2, 3]));
即便有推荐这个方案,实际运行也没有效果。
另外,使用如下写法:
console.log(arr.filter(nested => nested[0] !== 2 || nested[1] !== 3));
效率太低,我的实际业务场景中需要处理的子数组长度达数百项,上面的示例仅为简化演示。恳请各位提供可行的解决方案,谢谢!
首先明确之前方案失效的核心原因:JavaScript中数组属于引用类型,indexOf([2,3])中的[2,3]是新创建的数组对象,和原数组里的[2,3]引用地址不同,所以永远无法匹配到对应元素;同时findIndex需要传入回调函数而非直接传入目标数组,调用方式本身就是错误的。
针对子数组长度大、要求高性能的场景,分两种常用方案:
方案1:单次删除场景,用findIndex加数组等值判断
findIndex匹配到第一个符合条件的元素就会终止遍历,比filter遍历全数组的性能高很多,搭配通用数组等值判断函数即可适配任意长度的基础类型子数组:
// 仅适用于子数组元素全为基础类型(数字、字符串、布尔值、null、undefined)的场景 function isArrayEqual(a, b) { if (a.length !== b.length) return false; for (let i = 0; i < a.length; i++) { if (a[i] !== b[i]) return false; } return true; } const targetArr = [2, 3]; const deleteIndex = arr.findIndex(item => isArrayEqual(item, targetArr)); if (deleteIndex !== -1) { arr.splice(deleteIndex, 1); // 直接修改原数组,不需要生成新数组,性能更优 }
该方案单次操作的时间复杂度为O(n*m),n为外层数组长度,m为子数组长度,对于常规业务场景完全够用。
方案2:多次删除/查询场景,提前构建索引映射
如果你需要对同一个外层数组做多次子数组删除、查询操作,推荐提前把子数组序列化为唯一键存入Map,后续操作时间复杂度可以降到O(m + 1)(m为子数组序列化的时间):
// 初始化时仅执行一次,构建索引映射 const arrIndexMap = new Map(arr.map((item, index) => [item.join(','), index])); // 后续每次删除操作 const targetArr = [2, 3]; const targetKey = targetArr.join(','); if (arrIndexMap.has(targetKey)) { const deleteIndex = arrIndexMap.get(targetKey); arr.splice(deleteIndex, 1); // 如果删除后还需要继续操作,可根据需求更新Map:如果删除的是最后一个元素直接删键即可,否则建议重新生成Map // arrIndexMap.delete(targetKey); }
如果子数组包含特殊字符可能和分隔符冲突,可以替换为JSON.stringify(item)作为键,兼容性更强。
内容的提问来源于stack exchange,提问作者sasindumaheepala

