JS 两个数组,比较差值的时候,splice删除元素,会出现删不干净的情况

问题描述

JS 两个数组,如代码所示。为什么b数组内的1没有全部删除呢?求大神指点

相关代码

var a = [1];
var b = [1, 1, 1, 2, 5, 8]

a.forEach((item) => {
 b.forEach((val,index) => {
 if (val == item) {
 b.splice(index, 1);
 }
 });
});

console.log(b); // [ 1, 2, 5, 8 ]
阅读 5k
6 个回答

调用 splice 操作元素时,未被操作的元素会自动移位,不会出现 undefinedforEachval 对应的 index 是刚开始调用 forEach 时的 index。以

var a = [1.5];
var b = [1.1, 1.2, 1.3, 2, 5, 8];
a.forEach((item) => {
  b.forEach((val, index) => {
    if (val < item) {
      b.splice(index, 1);
    };
  });
});

为例,在 forEach 的第一次循环里,数组第一个元素被删除后,数组变为 [1.2, 1.3, 2, 5, 8],第二次循环中 val = 1.2, index = 2,满足条件,删去第二个元素,相当于原数组第三个元素,变为 [1.2, 2, 5, 8]

要解决这个问题,可以像 qinchao888 那样用 for,删去后 i-- 更正 i 值,也可以用更加语义化的 ES6 的 filter

var a = [1];
var b = [1, 1, 1, 2, 5, 8];
a.forEach((item) => {
  b = b.filter((val) => val !== item);
});

或者这样:(推荐)

var a = [1];
var b = [1, 1, 1, 2, 5, 8];
b = b.filter(val => !a.includes(val));

qinchao888 的方法不会创建新数组,保留了原数组的内存引用,性能上似乎也更好。这里给出的两种 ES6 的方法都会创建新数组,再重新给 b 赋值,但语义比较清晰。这两种方法中,第一种可能会在内存中创建多个数组,a 有几个元素创几个;第二种方法既简单又只会在内存中创建一个新数组,比较推荐。


Array.prototype.splice() | MDN
Array.prototype.forEach() | MDN
Array.prototype.filter() | MDN
Array.prototype.includes() | MDN

如果想删除,用逆序循环

第一遍 index === 0

var a = [1];
var b = [1(被删除), 1, 1, 2, 5, 8]

第二遍 index === 1

var a = [1];
var b = [1, 1(被删除), 2, 5, 8]

第三遍 index === 2

var a = [1];
var b = [1, 2, 5(比较这个), 8]

第三遍 index === 3

var a = [1];
var b = [1, 2, 5, 8(比较这个)]

结果 [1, 2, 5, 8]

不能使用forEach,使用splice删除元素后,索引index的值仍然是累加的。会使一些元素未遍历到。

a.forEach((item) => {
  for (var i = 0; i < b.length; i++) {
    if (item === b[i]) {
      b.splice(i, 1)
      i--
    }
  }
});

不应该在循环中增删数组元素。
因为会导致删除元素后的元素直接补到当前已删除元素的位置,占用当前下标,而下一次遍历的时候,下标+1自然而然跳过了这个元素。
逆序遍历可以解决这个问题,更稳妥的办法是使用filter。
找出b中不在a中的元素, 写法一:

const result = b.filter(i => !a.includes(i))

写法二、

const map = a.reduce((r, i) => (r[i] = 1, r), {})
const result = b.filter(i => !map[i])

写法二比写法一要优,写法一时间复杂度O(m x n),写法二时间复杂度O(m + n)。

var a = [1];
var b = [1, 1, 1, 2, 5, 8];
var result= b.reduce((_result_,b_item)=>{
    if(a.indexOf(b_item)===-1){
        _result_.push(b_item);
    }
    return _result_;
},[]);
console.log('b after clear:',result);
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏