【问题标题】:filterRangeInPlace(arr, a, b) that gets an array arr and removes from it all values except those that are between a and bfilterRangeInPlace(arr, a, b) 获取数组 arr 并从中删除除 a 和 b 之间的所有值之外的所有值
【发布时间】:2025-12-02 00:35:01
【问题描述】:

下面的函数很好用

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

【问题讨论】:

    标签: javascript html arrays foreach


    【解决方案1】:

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

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

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

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

    要获得所需的效果,您可以使用Shubham Khatri's answer,它不会改变数组,但会覆盖它。这是我会选择的方法。

    但是,如果您真的想用 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 循环更糟糕。

    【讨论】:

      【解决方案2】:

      您不能使用 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);

      【讨论】:

        最近更新 更多