嵌套for循环比较对象数组:删除匹配元素残留问题排查
问题:移除数组中匹配对象时残留元素的原因与解决办法
我有两个对象数组arr1和arr2,二者元素的属性值完全相同但顺序不同。需求是移除arr1中与arr2所有属性值都匹配的对象,但使用嵌套for循环实现后,console.log输出的arr1始终残留{ foo: '', bar: '594' }对象。
数组代码
const arr1 = [ { foo: '061', bar: '591' }, { foo: '061', bar: '592' }, { foo: '070', bar: '593' }, { foo: '', bar: '594' } ] const arr2 = [ { foo: '061', bar: '591' }, { foo: '061', bar: '592' }, { foo: '', bar: '594' }, { foo: '070', bar: '593' } ]
原嵌套for循环代码
for (let i = 0; i < arr1.length; i++) { for (let j = 0; j < arr2.length; j++) { if (arr1[i].foo === arr2[j].foo && arr1[i].bar === arr2[j].bar) { arr1.splice(i, 1) } } }
问题原因
核心问题是使用splice删除元素后,数组长度会缩短,但外层循环的i仍在递增,导致跳过了部分元素:
- 初始
arr1长度为4,当i=0时,匹配到元素并splice(0,1),arr1长度变为3,此时i递增到1; - 当
i=1时,匹配到{ foo: '070', bar: '593' }并splice(1,1),arr1长度变为2,i递增到2; - 此时
i=2不满足i < arr1.length(2 < 2 为假),循环直接结束,最后一个元素{ foo: '', bar: '594' }根本没被遍历到,所以残留了下来。
解决办法
办法1:倒序遍历数组
倒序遍历的时候,删除当前元素不会影响前面未遍历的元素索引,避免跳过问题:
for (let i = arr1.length - 1; i >= 0; i--) { for (let j = 0; j < arr2.length; j++) { if (arr1[i].foo === arr2[j].foo && arr1[i].bar === arr2[j].bar) { arr1.splice(i, 1); break; // 找到匹配就跳出内层循环,不用继续比对 } } }
办法2:删除元素后回退索引
当删除元素时,手动让i减1,抵消外层循环的递增操作,保证每个元素都被遍历到:
for (let i = 0; i < arr1.length; i++) { let isMatched = false; for (let j = 0; j < arr2.length; j++) { if (arr1[i].foo === arr2[j].foo && arr1[i].bar === arr2[j].bar) { arr1.splice(i, 1); isMatched = true; break; } } if (isMatched) { i--; // 回退索引,避免跳过下一个元素 } }
办法3:使用filter创建新数组(推荐)
不修改原数组,而是通过filter和some方法生成过滤后的新数组,逻辑更清晰,也不会出现索引问题:
const filteredArr1 = arr1.filter(item1 => { // 保留arr2中不存在匹配项的元素 return !arr2.some(item2 => item1.foo === item2.foo && item1.bar === item2.bar); }); // 如果需要覆盖原数组 // arr1 = filteredArr1;
内容的提问来源于stack exchange,提问作者Henry
相关产品推荐
相关产品推荐

