By dzm


2012-03-27 01:44:07 8 Comments

I have the following for loop, and when I use splice() to remove an item, I then get that 'seconds' is undefined. I could check if it's undefined, but I feel there's probably a more elegant way to do this. The desire is to simply delete an item and keep on going.

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);
    }           
}

12 comments

@Bhanuprakash D 2018-11-06 16:24:54

There are lot of wonderful answers on this thread already. However I wanted to share my experience when I tried to solve "remove nth element from array" in ES5 context.

JavaScript arrays have different methods to add/remove elements from start or end. These are:

arr.push(ele) - To add element(s) at the end of the array 
arr.unshift(ele) - To add element(s) at the beginning of the array
arr.pop() - To remove last element from the array 
arr.shift() - To remove first element from the array 

Essentially none of the above methods can be used directly to remove nth element from the array.

A fact worth noting is that this is in contrast with java iterator's using which it is possible to remove nth element for a collection while iterating.

This essentially leaves us with only one array method Array.splice to perform removal of nth element (there are other things you could do with these methods as well, but in the context of this question I am focusing on removal of elements):

Array.splice(index,1) - removes the element at the index 

Here is the code copied from original answer (with comments):

var arr = ["one", "two", "three", "four"];
var i = arr.length; //initialize counter to array length 

while (i--) //decrement counter else it would run into IndexOutBounds exception
{
  if (arr[i] === "four" || arr[i] === "two") {
    //splice modifies the original array
    arr.splice(i, 1); //never runs into IndexOutBounds exception 
    console.log("Element removed. arr: ");

  } else {
    console.log("Element not removed. arr: ");
  }
  console.log(arr);
}

Another noteworthy method is Array.slice. However the return type of this method is the removed elements. Also this doesn't modify original array. Modified code snippet as follows:

var arr = ["one", "two", "three", "four"];
var i = arr.length; //initialize counter to array length 

while (i--) //decrement counter 
{
  if (arr[i] === "four" || arr[i] === "two") {
    console.log("Element removed. arr: ");
    console.log(arr.slice(i, i + 1));
    console.log("Original array: ");
    console.log(arr);
  }
}

Having said that, we can still use Array.slice to remove nth element in the following way and as you can observe it is lot more code (hence inefficient)

var arr = ["one", "two", "three", "four"];
var i = arr.length; //initialize counter to array length 

while (i--) //decrement counter 
{
  if (arr[i] === "four" || arr[i] === "two") {
    console.log("Array after removal of ith element: ");
    arr = arr.slice(0, i).concat(arr.slice(i + 1));
    console.log(arr);
  }

}

The Array.slice method is extremely important to achieve immutability in functional programming à la redux

@0xc0de 2013-09-06 08:01:50

Although your question is about deleting elements from the array being iterated upon and not about removing elements (in addition to some other processing) efficiently, I think one should reconsider it if in similar situation.

The algorithmic complexity of this approach is O(n^2) as splice function and the for loop both iterate over the array (splice function shifts all elements of array in the worst case). Instead you can just push the required elements to the new array and then just assign that array to the desired variable (which was just iterated upon).

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;

Since ES2015 we can use Array.prototype.filter to fit it all in one line:

Auction.auctions = Auction.auctions.filter(auction => --auction.seconds >= 0);

@user1106925 2012-03-27 01:50:52

The array is being re-indexed when you do a .splice(), which means you'll skip over an index when one is removed, and your cached .length is obsolete.

To fix it, you'd either need to decrement i after a .splice(), or simply iterate in reverse...

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

This way the re-indexing doesn't affect the next item in the iteration, since the indexing affects only the items from the current point to the end of the Array, and the next item in the iteration is lower than the current point.

@Rubinsh 2017-11-29 07:28:04

If you are e using ES6+ - why not just use Array.filter method?

Auction.auctions = Auction.auctions.filter((auction) => {
  auction['seconds'] --;
  return (auction.seconds > 0)
})  

Note that modifying the array element during filter iteration only works for objects and will not work for array of primitive values.

@user8533067 2017-08-29 14:06:09

You can just look through and use shift()

@Ivan 2017-08-29 14:41:00

Please add an example using this method.

@Dmitry Ragozin 2016-12-15 15:33:46

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);
        i--;
        len--;
    }
}

@B001ᛦ 2016-12-15 15:53:44

A good answer will always have an explanation of what was done and why it was done in such a manner, not only for the OP but for future visitors to SO.

@Pablo 2016-11-17 16:40:28

Another simple solution to digest an array elements once:

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
}

@daniel.szaniszlo 2016-02-26 12:34:38

Here is another example for the proper use of splice. This example is about to remove 'attribute' from 'array'.

for (var i = array.length; i--;) {
    if (array[i] === 'attribute') {
        array.splice(i, 1);
    }
}

@Zon 2016-01-28 15:54:43

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;

@frattaro 2015-01-24 03:49:17

This is a pretty common issue. The solution is to loop backwards:

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);
    }
}

It doesn't matter if you're popping them off of the end because the indices will be preserved as you go backwards.

@Aesthete 2013-09-06 08:12:44

Auction.auction = Auction.auctions.filter(function(el) {
  return --el["seconds"] > 0;
});

@Marc 2012-03-27 01:50:20

Recalculate the length each time through the loop instead of just at the outset, e.g.:

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

That way you won't exceed the bounds.

EDIT: added a decrement in the if statement.

Related Questions

Sponsored Content

78 Answered Questions

[SOLVED] How do I remove a particular element from an array in JavaScript?

  • 2011-04-23 22:17:18
  • Walker
  • 5649172 View
  • 7022 Score
  • 78 Answer
  • Tags:   javascript arrays

39 Answered Questions

[SOLVED] Loop through an array in JavaScript

35 Answered Questions

[SOLVED] How to remove item from array by value?

  • 2010-10-17 17:43:34
  • MacMac
  • 814406 View
  • 741 Score
  • 35 Answer
  • Tags:   javascript arrays

32 Answered Questions

[SOLVED] How do I break out of nested loops in Java?

  • 2009-05-20 09:07:43
  • boutta
  • 1027290 View
  • 1668 Score
  • 32 Answer
  • Tags:   java loops

21 Answered Questions

[SOLVED] How to loop through a plain JavaScript object with the objects as members?

  • 2009-05-28 16:18:14
  • edt
  • 1445017 View
  • 1404 Score
  • 21 Answer
  • Tags:   javascript

14 Answered Questions

[SOLVED] How to insert an item into an array at a specific index (JavaScript)?

35 Answered Questions

[SOLVED] How do I loop through or enumerate a JavaScript object?

11 Answered Questions

[SOLVED] Looping through the content of a file in Bash

  • 2009-10-05 17:52:54
  • Peter Mortensen
  • 1272210 View
  • 1109 Score
  • 11 Answer
  • Tags:   linux bash loops unix io

11 Answered Questions

[SOLVED] Ways to iterate over a list in Java

15 Answered Questions

[SOLVED] C# loop - break vs. continue

  • 2008-08-08 21:49:01
  • Seibar
  • 679235 View
  • 729 Score
  • 15 Answer
  • Tags:   c# loops enumeration

Sponsored Content