遍历数组并删除项目,而不会中断循环

JavaScript

番长猴子古一

2020-03-13

我有以下for循环,当我splice()用来删除项目时,然后得到的“秒数”是不确定的。我可以检查它是否未定义,但是我觉得可能有一种更优雅的方法来执行此操作。愿望是简单地删除一个项目并继续进行。

for (i = 0, len = Auction.auctions.length; i < len; i++) {
    auction = Auction.auctions[i];
    Auction.auctions[i]['seconds'] --;
    if (auction.seconds < 0) { 
        Auction.auctions.splice(i, 1);
    }           
}

第1519篇《遍历数组并删除项目,而不会中断循环》来自Winter(https://github.com/aiyld/aiyld.github.io)的站点

7个回答
Green达蒙 2020.03.13

You can just look through and use shift()

乐小宇宙 2020.03.13

Try to relay an array into newArray when looping:

var auctions = Auction.auctions;
var auctionIndex;
var auction;
var newAuctions = [];

for (
  auctionIndex = 0; 
  auctionIndex < Auction.auctions.length;
  auctionIndex++) {

  auction = auctions[auctionIndex];

  if (auction.seconds >= 0) { 
    newAuctions.push(
      auction);
  }    
}

Auction.auctions = newAuctions;
路易伽罗 2020.03.13

这是一个很常见的问题。解决方案是向后循环:

for (var i = Auction.auctions.length - 1; i >= 0; i--) {
    Auction.auctions[i].seconds--;
    if (Auction.auctions[i].seconds < 0) { 
        Auction.auctions.splice(i, 1);
    }
}

是否从头开始弹出都没关系,因为索引会在您向后移动时保留。

飞云Mandy 2020.03.13

尽管您的问题是关于从要迭代的数组中删除元素而不是有效地删除元素(除了某些其他处理),但我认为如果处于类似情况,则应该重新考虑它。

这种方法的算法复杂性在于O(n^2),剪接函数和for循环都在数组上迭代(在最坏的情况下,剪接函数会移动数组的所有元素)。相反,您可以将所需的元素推到新数组中,然后将该数组分配给所需的变量(刚刚对其进行迭代)。

var newArray = [];
for (var i = 0, len = Auction.auctions.length; i < len; i++) {
    auction = Auction.auctions[i];
    auction.seconds--;
    if (!auction.seconds < 0) { 
        newArray.push(auction);
    }
}
Auction.auctions = newArray;

从ES2015开始,我们可以Array.prototype.filter将所有内容合而为一:

Auction.auctions = Auction.auctions.filter(auction => --auction.seconds >= 0);
Sam前端 2020.03.13

一次消化数组元素的另一种简单解决方案:

while(Auction.auctions.length){
    // From first to last...
    var auction = Auction.auctions.shift();
    // From last to first...
    var auction = Auction.auctions.pop();

    // Do stuff with auction
}
乐A 2020.03.13
Auction.auctions = Auction.auctions.filter(function(el) {
  return --el["seconds"] > 0;
});
Near逆天 2020.03.13

当您执行时,该数组将被重新索引.splice(),这意味着删除索引时将跳过索引,并且缓存.length已过时。

要解决此问题,您可能需要在i后面.splice(),或者简单地反向迭代...

var i = Auction.auctions.length
while (i--) {
    ...
    if (...) { 
        Auction.auctions.splice(i, 1);
    } 
}

这样,重新索引不会影响迭代中的下一个项目,因为索引仅影响从当前点到数组末尾的项目,并且迭代中的下一个项目低于当前点。

问题类别

JavaScript Ckeditor Python Webpack TypeScript Vue.js React.js ExpressJS KoaJS CSS Node.js HTML Django 单元测试 PHP Asp.net jQuery Bootstrap IOS Android