循环删除数组中元素的正确方法
提起循环删除数组中的元素,最先想到的就是使用for循环和数组的splice方法来实现(正序循环删除方法),如下代码用来实现删除数组中大于2的元素:
let arr = [1, 2, 3, 4, 5, 4, 3, 2, 1];
for (let i = 0, len = arr.length; i < len; i++) {
if (arr[i]> 2) {
arr.splice(i, 1);
}
}
console.log(arr) // [1, 2, 4, 4, 2, 1]
通过循环删除后,将结果打印出来,发现结果中出现了4,显然没有达到想要的结果,这是因为在上述循环删除过程中由于删除操作的存在,使得数组中索引值对应的元素值发生变化而产生的,如下图所示:
当循环到索引值为2的位置时,该位置上对应的数值为3,3满足大于2的条件,需要删除,删除之后,整个数组中的元素会向前移动一位,此时索引值为2的位置上的数值为4,之后会继续循环到索引值为3的位置,索引值为2的位置上的值就不会再被遍历,因此元素4得以保留,之后的过程与此类似。
由于删除操作使得数组中索引值对应的元素值发生变化从而导致循环删除结果不准确,为了避免这种情况,可以采用以下正确方法:
1、倒序循环删除
let arr = [1, 2, 3, 4, 5, 4, 3, 2, 1];
for (let i = arr.length - 1; i >= 0; i--) {
if (arr[i] > 2) {
arr.splice(i, 1);
}
}
console.log(arr) // [1, 2, 2, 1]
倒序循环删除与正序循环删除最大区别是:在倒序循环删除中,它的删除操作不会影响还未循环遍历的元素;这就使得即使删除之后数组中元素会向前移动一位,也不会让未遍历的元素跳过遍历。原理图如下:
2、正序循环删除,删除操作后将索引值减1
上面分析中可知在正序循环删除方法中,删除操作会使得对应索引值位上的元素清空,整个数组中的元素向前移动一位,补位的元素会填充到执行删除操作的索引值位置上,移位之后如果不进行任何操作继续下一个循环,会导致补位元素跳过遍历,为了防止这种补位元素跳过遍历现象,应该在删除操作后将索引值减1,对执行删除操作的索引值位置再进行一次遍历。
let arr = [1, 2, 3, 4, 5, 4, 3, 2, 1];
for (let i = 0, len = arr.length; i < len; i++) {
if (arr[i]> 2) {
arr.splice(i, 1);
i--;
}
}
console.log(arr) // [1, 2, 2, 1]
原理图如下:
参考文献:
[1] 循环删除数组元素的几种姿势