【问题标题】:How to iterate over an array and remove elements in JavaScript [duplicate]如何在 JavaScript 中迭代数组并删除元素 [重复]
【发布时间】:2013-04-27 11:33:12
【问题描述】:

我有一个元素数组,需要从中删除某些元素。问题是 JavaScript 似乎没有 for each 循环,如果我使用 for 循环,我会遇到问题,它基本上试图检查数组边界之外的元素,或者由于索引更改而丢失数组中的元素.让我告诉你我的意思:

var elements = [1, 5, 5, 3, 5, 2, 4];
for(var i = 0; i < elements.length; i++){
    if(elements[i] == 5){
        elements.splice(i, 1);
    }
}

问题是当元素[1]被移除时,元素[2]变成了元素[1]。所以第一个问题是某些元素从未被检查过。另一个问题是 .length 发生了变化,如果我对边界进行硬编码,那么我可能会尝试检查超出数组边界的元素。那么,完成这个极其简单的事情的最佳方法是什么?

【问题讨论】:

标签: javascript iteration bounds


【解决方案1】:

var elements = [1, 5, 5, 3, 5, 2, 4];    
var i = elements.length;
while (i--) {
    if (elements[i] == 5) {
        elements.splice(i, 1);
    }
}
console.log(elements);

【讨论】:

  • 就代码可读性而言,这个答案很可爱
【解决方案2】:

您可以在删除项目时简单地减少 i

var elements = [1, 5, 5, 3, 5, 2, 4];

var l = elements.length;
for(var i = 0; i < l; i++){
    if(elements[i] == 5){
        elements.splice(i, 1);
        i--;
    }
}

console.log(elements);

【讨论】:

    【解决方案3】:

    使用Array.shift()

    var array = [1, 2, 3, 'a', 'b', 'c'];
    while (array.length > 0) {
      console.log(array.shift());
    }
    

    编辑:可能不符合规格。我误读了这个问题(仅删除 某些 元素)并且太急于添加尚未提及的方法...

    【讨论】:

    • 正如您在编辑中所说,这实际上并不能回答问题,但它确实回答了我试图搜索的问题。谢谢。
    【解决方案4】:

    您可以在这里使用filter 方法:

    var elements = [1, 5, 5, 3, 5, 2, 4].filter(function(a){return a !== 5;});
    //=> elements now [1,3,2,4]
    

    或者如果你不想碰elements

    var elementsfiltered
       ,elements = [1, 5, 5, 3, 5, 2, 4]
                    .filter( function(a){if (a!==5) this.push(a); return true;},
                             elementsfiltered = [] );
       //=> elementsfiltered = [1,3,2,4], elements = [1, 5, 5, 3, 5, 2, 4]
    

    filterMDN documentation

    您也可以扩展Array.prototype

    Array.prototype.remove = Array.prototype.remove || function(val){
        var i = this.length;
        while(i--){
            if (this[i] === val){
                this.splice(i,1);
            }
        }
    };
    var elements = [1, 5, 5, 3, 5, 2, 4];
    elements.remove(5);
    //=> elements now [1,3,2,4]
    

    【讨论】:

    • 虽然创建一个新数组,过滤器确实是一个不错的解决方案,但 OP 实际上确实询问了关于删除内联元素的问题,最好举个例子。跨度>
    • 似乎不必要地偏离了原始代码。 OP 可以通过在拼接后减少 i 来保留他现有的代码。
    • 我个人觉得过滤器更安全,因为递减我可能会导致边缘情况,就好像零元素存在等
    【解决方案5】:

    这是使用Array.indexOfwhileArray.splice 删除内联元素的示例。

    var elements = [1, 5, 5, 3, 5, 2, 4];
    var remove = 5;
    var index = elements.indexOf(remove);
    
    while (index !== -1) {
        elements.splice(index, 1);
        index = elements.indexOf(remove);
    }
    
    console.log(elements);
    

    开启jsfiddle

    【讨论】:

    • 低效 O(n^2) 算法被否决
    • 我从来没有对效率提出任何要求,问题并不关心这一点,而是在执行内联元素删除时如何处理不断变化的数组长度。这是一个 jsPerf,以便您可以将高效版本作为答案并将其与发布的其他答案进行比较。 jsperf.com/soq-iterate-over-an-array-and-remove
    • 处理数组长度变化的规范方法是从数组的末尾开始并向后工作。或者,如果您删除了当前元素,则可以从当前位置向前工作并且不增加。相反,每次找到匹配项时,您的方法从第零个元素开始,从而反复遍历相同的元素。这是一个非常糟糕的算法,永远不应该使用。
    • 好吧,这很奇怪——我试过了,而且(在这个小样本集上)它慢得多。我还不知道为什么。 jsperf.com/soq-iterate-over-an-array-and-remove/2
    • 我稍微更改了测试用例 - 现在 fromIndex 用例的运行速度非常轻微...jsperf.com/soq-iterate-over-an-array-and-remove/3
    【解决方案6】:

    从头开始!

    var elements = [1, 5, 5, 3, 5, 2, 4];
    for(var i = elements.length -1; i >= 0 ; i--){
        if(elements[i] == 5){
            elements.splice(i, 1);
        }
    }
    

    【讨论】:

    • +1 用于从末尾开始,以避免由于 OP 提到的长度变化而跳过元素。
    • for (var i = elements.length; i--;) 可能是更常见的写法。
    • 我希望我能不止一次地对此表示赞同。奥卡姆正在向你发送一个来自伟大彼岸的宇宙高五。
    • 认真的吗?一个 O(n^2) 的答案,有 147 个赞成票,没有反对票?这是给你的反对票。
    • 这不只是 O(n) 吗?它只循环整个数组一次。
    猜你喜欢
    • 1970-01-01
    • 2018-09-04
    • 2020-05-21
    • 2017-03-21
    • 2010-11-09
    • 2013-01-23
    • 2012-06-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多