filterRangeInPlace(arr,a,b),用于获取数组arr并从中删除除a和b之间的值之外的所有值



下面的函数工作得很好

function filterRangeInPlace(arr, a, b) {
for (let i = 0; i < arr.length; i++) {
let val = arr[i];
// remove if outside of the interval
if (val < a || val > b) {
arr.splice(i, 1);
i--;
}
}
}
arr=[2,3,4,5,6,7,1,0,2,12,11];
filterRangeInPlace(arr,1,5);
alert(arr);

但我想对forEach执行相同的功能

let filterRange = (arr, a, b) => {
arr.forEach((item, i) => {
val=item;debugger;
if (val < a || val > b) {
arr.splice(i, 1);
i--;
}
})
}
arr=[2,3,4,5,6,7,1,0,2,12,11];
filterRange(arr,1,5);
alert(arr);

我试过了,但没能得到正确的答案。它不能像正常迭代一样工作。有没有其他方法可以使用相同的foreach

您不能使用forEach对数组进行就地修改,因为您无法控制forEach 内部循环的索引

forEach的一个微不足道的实现就像

Array.prototype.forEach = function(cb) {
const arr = this;
for(var i = 0; i < arr.length; i++) {
cb.call(arr, arr[i], i, arr);
}
}

如果你看看上面的人,回调只是用arr[i]值调用的,如果数组发生了变异,你将无法变异内部迭代器

对于像您这样的用例,您应该使用Array.prototype.filter

let filterRange = (arr, a, b) => {
return arr.filter((item, i) => {
val=item;
if (val < a || val > b) {
return false;
}
return true;
})
}
var arr=[2,3,4,5,6,7,1,0,2,12,11];
arr = filterRange(arr,1,5);
alert(arr);

forEach的调用创建了在开始处理之前要处理的元素范围。

因此,当您访问i时,您是在调用forEach时访问该值,而不是在运行回调函数时。此外,顺便说一句,i--forEach版本的算法中什么都不做,因为回调的其他实例无法访问它。

此外,如果移除一个元素,那么下一个元素将被跳过,因为这些元素将被移动到与迭代器对齐的位置。

那么,处理的是2,3,4,5,6,[skip],1,0,[skip:],12,[skip/]。这就是为什么在输出中仍然可以看到7和11。

为了获得所需的效果,你可以使用Shubham Khatri的答案,它不会改变数组,而是覆盖它。这是我会选择的方法。

然而,如果你真的想用forEach突变数组,你需要跟踪你偏离了多远,并在前进的过程中保持正确:

let filterRange = (arr, a, b) => {
let offset = 0;
arr.forEach((item, i, inPlace) => {
if (item < a || item > b) {
inPlace.splice(i, 1);
offset++;
}
let temp_offset = offset;
while(temp_offset > 0)
{
let offset_item = inPlace[i-temp_offset];
if (offset_item < a || offset_item > b) {
inPlace.splice(i-temp_offset, 1);
offset++;
}
temp_offset--;
}
})
}
arr=[2,3,4,5,6,7,1,0,2,12,11,4,99,2];
filterRange(arr,1,5);
console.log('result',arr);

这个方法比原来的for循环更糟糕。

最新更新