如何在JavaScript中删除二维数组中的重复子数组?
删除二维数组中重复子数组的解决方案
需求说明
需要从ground二维数组中删除所有与deleteBlock内子数组内容完全重复的项。
原始数据
let ground = [ [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], [1,3,3,7,7,7,7,8,8,4,4,4,2,2,3,7,1], [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], ] let deleteBlock = [[1,3,3,7,7,7,7,8,8,4,4,4,2,2,3,7,1]]
你尝试方法的问题分析
第一种方法
let ans = ground.filter((r,idx) => { for(let i =0; i < deleteBlock.length;i++) { if(r === deleteBlock[i]) { ground.splice(idx, 1) } } })
- 引用类型比较错误:数组是引用类型,
===比较的是内存地址而非内容,所以r === deleteBlock[i]永远为false,不会触发splice。 - filter使用错误:
filter的回调需要返回布尔值决定是否保留元素,此代码没有返回值,且在filter中直接用splice修改原数组会打乱遍历顺序,导致结果异常。
第二种方法
ground.filter((r) => deleteBlock.forEach(ele=> r.includes(ele)))
- forEach无返回值:
forEach不会返回任何值,所以filter的回调始终得到undefined(视为假值),最终会过滤掉所有元素。 - includes误用:
r.includes(ele)是判断数组r是否包含ele这个整体(即子数组是否是r的元素),而非判断两个数组内容是否相等。
正确解决方案
方法一:逐个元素比较(直观易懂)
先写一个辅助函数判断两个数组内容是否完全相等,再用filter结合some过滤:
// 辅助函数:判断两个数组内容是否完全一致 function arraysEqual(arr1, arr2) { if (arr1.length !== arr2.length) return false; for (let i = 0; i < arr1.length; i++) { if (arr1[i] !== arr2[i]) return false; } return true; } // 过滤ground数组 const filteredGround = ground.filter(subArr => { // 只要deleteBlock中有一个子数组和当前subArr相等,就过滤掉它 return !deleteBlock.some(block => arraysEqual(subArr, block)); });
方法二:转字符串存Set(性能更优)
把deleteBlock中的子数组转成JSON字符串存入Set,利用Set的O(1)查找效率快速判断,适合处理大数据量:
// 将deleteBlock的子数组转为字符串存入Set const deleteStringSet = new Set(deleteBlock.map(block => JSON.stringify(block))); // 过滤ground:当前子数组转字符串后不在Set中则保留 const filteredGround = ground.filter(subArr => { return !deleteStringSet.has(JSON.stringify(subArr)); });
验证结果
两种方法都会得到去掉了目标子数组的filteredGround,原ground中倒数第二个子数组会被正确删除。
内容的提问来源于stack exchange,提问作者kirk0201
相关产品推荐
相关产品推荐

