【问题标题】:Remove array item using for...of loop使用 for...of 循环删除数组项
【发布时间】:2020-01-05 06:57:27
【问题描述】:

我正在尝试编辑一个数组并删除不满足特定条件的元素。如果我将reverse for loop 与.splice(index,n) 结合使用,则代码可以正常工作。我坚持使用 ES6 for...of 循环实现相同的功能

let array=[1,2,3];
//reverse for loop
for(var i=array.length - 1; i>=0; i--) {
  if(array[i]>=2) {
    /*Collect element before deleting it.*/
    array.splice(i,1);
  }
} 
console.log(array);
// returns [1]

用于..of

let array=[1,2,3];
for(let entry of array) {
    if(entry>=2) {
        let index = array.indexOf(entry);

        /*The array is being re-indexed when I apply 
        .splice() - the loop will skip over an index
        when one element of array is removed*/

        array.splice(index, 1);
    }
} 
console.log(array);
//returns [1,3]

有没有办法使用for...of 循环来实现此功能,还是我必须坚持使用reverse for loop

更新
我需要将不符合 filter() 或 reverse for loop 函数删除的元素的条目收集到辅助数组中。

【问题讨论】:

  • 在遍历数组时不要使用拼接,因为它会改变原始数组
  • 非常复杂。改用.filter,更容易
  • filter 正是您所需要的。对正在迭代的数组进行变异是一种不好的做法。
  • “如果我将反向 for 循环与 .splice(index,n) 结合使用,代码就可以正常工作。” 这是正确的做法。你也可以使用whilelike this

标签: javascript loops for-of-loop


【解决方案1】:

您不能合理地为此使用for-of。如果您在迭代期间删除“当前”条目,您将跳过下一个条目,因为数组迭代器的指定方式(它们使用条目的索引)。您可以通过这个人为的示例看到这一点:

const array = [1, 2, 3];
for (const entry of array) {
    console.log(entry);
    if (entry === 2) {
        array.splice(1, 1);
    }
}
console.log(array);

注意条目3 没有循环迭代。

我建议要么坚持你的反向 for 循环,要么使用 filter 来生成一个只包含你想要保留的条目的新数组。

使用filter:

let array = [1, 2, 3];
array = array.filter(entry => entry < 2);
console.log(array);

我在上面说“合理”是因为,当然,总有办法。您可以遍历数组的副本并在其外部维护index:

const array = [1, 2, 3];
let index = 0;
for (const entry of [...array]) {
    if (entry >= 2) {
        array.splice(index, 1);
    } else {
        ++index;
    }
}
console.log(array);

与替代方案相比,这似乎不合理,除非当然有限制因素迫使您这样做。 :-)

【讨论】:

  • 如果您在迭代期间删除“当前”条目,您将跳过下一个条目,因为数组迭代器的指定方式(它们使用条目的索引)。为什么 for of 迭代器的行为是这样的?请参考一些 Mozilla 文档。我想详细探索一下。
  • 在移除数组元素之前需要做其他操作。我可以使用filter 函数实现相同的功能吗? (见更新的问题)。
  • @MobeenSarwar - 因为,正如我所说,他们使用索引。见the specification。
  • @JuneM3ta - 还有哪些其他操作?你可以在filter回调中做任何你想做的事情...
  • @T.J Crowder 如果我有array = array.filter(function(entry) { return entry&lt;2; }); array=[1,2,3] 我可以在从数组中过滤之前从filter() 函数中访问元素2,3 吗?或者,我是否必须创建一个单独的过滤函数来存储与该条件不匹配的元素(在单独的数组中),以便我可以在丢弃它们之前使用它们?
【解决方案2】:

根据@T.J's answer,使用for...of循环时:

如果您在迭代期间删除“当前”条目,您将跳过下一个条目,因为数组迭代器的指定方式(它们使用条目的索引)。

这留下了另外两个选项,使用reverse for loop 和filter 函数。前面提到过,在删除之前需要对当前数组元素做一个操作。

1.使用.filter()函数
并参考@T.J's Comment

let array = [1,2,3];
let collection = [];

array = array.filter(function(entry) {
    if(entry>=2) {
        collection.push(entry);
    } 
    return entry <2;
});

console.log(collection); //returns [2,3]
console.log(array); //returns [1]

2。使用reverse for loop

let array = [1,2,3];
let collection = [];

for(var i=array.length - 1; i>=0; i--) {
  if(array[i]>=2) {
     collection.push(array[i]);
     array.splice(i,1);
  }
}

console.log(collection); //returns [2,3]
console.log(array); //returns [1] 

本例中的filter()函数需要额外的步骤来临时保存不满足条件的元素。 reverse for loop 提供了一种更简洁的方式来实现这一目标。

【讨论】:

  • 我也在考虑这个案子。
  • 您没有说需要收集您删除的条目(而您的第二个解决方案没有)。
  • @T.J.Crowder 我已经更新了我的答案。此外,我更关注 for...of 循环的操作。不过,我的错,应该早点提到!
【解决方案3】:

迭代器在删除数组中的当前条目时跳过下一个条目。所以你应该这样来达到你想要的结果。

let array = [1,2,3];
let array_new = [1,2,3];
for(let entry of array) {
if(entry>=2) {
    let index = array_new.indexOf(entry);
    array_new.splice(index, 1);
}
} 
console.log(array_new);
//returns [1]

【讨论】:

  • 在这种情况下,reverse for loop 提供了一个更干净的选择:)。见this answer
  • @JuneM3ta 是的
猜你喜欢
  • 2018-07-10
  • 1970-01-01
  • 1970-01-01
  • 2020-07-10
  • 1970-01-01
  • 1970-01-01
  • 2021-12-25
相关资源
最近更新 更多