How to iterate over an array and remove elements in JavaScript

86,106

Solution 1

Start from the top!

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

Solution 2

You could use the filter method here:

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

Or if you don't want to touch 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]

See MDN documentation for filter

Alternatively you can extend the 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]

Solution 3

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

Solution 4

You could simply decrement i whenever you remove an item.

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

Solution 5

Using Array.shift():

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

Edit: Probably does not suit the specs. I misread the question (only remove certain elements) and was too eager instead to add a method that was not mentioned yet...

Share:
86,106

Related videos on Youtube

Captain Stack
Author by

Captain Stack

I am a full stack engineer who specializes in web technology, especially JavaScript and Ruby frameworks. I am deeply interested in the application of technology to furthering human well-being which is what inspired me to study informatics and human-computer interaction at the University of Washington.

Updated on July 05, 2022

Comments

  • Captain Stack
    Captain Stack almost 2 years

    I have an array of elements and need to remove certain ones from it. The problem is that JavaScript doesn't seem to have a for each loop and if I use a for loop I run into problems with it basically trying to check elements beyond the bounds of the array, or missing elements in the array because the indexes change. Let me show you what I mean:

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

    The problem is that when elements[1] is removed, elements[2] becomes elements[1]. So first problem is that some elements are never examined. The other problem is that .length changes and if I hard code the bounds, then I might be trying to examine elements beyond the bounds of the array. So what's the best way to do this incredibly simple thing?

  • Xotic750
    Xotic750 almost 11 years
    While creating a new array, which filter does, is not a bad suggestion as a solution, the OP does actually ask about removing elements inline and it would seem best to give an example of that.
  • Xotic750
    Xotic750 almost 11 years
    +1 for starting from the end to avoid skipping elements due to the changing length that the OP has mentioned.
  • Dagg Nabbit
    Dagg Nabbit almost 11 years
    for (var i = elements.length; i--;) is probably the more common way to write it.
  • Dagg Nabbit
    Dagg Nabbit almost 11 years
    Seems like an unnecessary departure from the original code. OP could keep his existing code by decrementing i after the splice.
  • Xotic750
    Xotic750 almost 11 years
    @Dagg Nabbit, one thing to note with that shorthand is that it will throw errors in jslint, if you should use such a tool for static code analysis (and of course the "--").
  • Dagg Nabbit
    Dagg Nabbit almost 11 years
    @Xotic750 yeah, jslint throws silly errors. =/
  • Alnitak
    Alnitak over 9 years
    downvoted for inefficient O(n^2) algorithm
  • Xotic750
    Xotic750 over 9 years
    I never made any claims on efficiency, and the question didn't concern that, but how you can deal with a changing array length when performing inline element removal. Here is a jsPerf so that you can give your efficient version as an answer and compare it with other answers posted. jsperf.com/soq-iterate-over-an-array-and-remove
  • Alnitak
    Alnitak over 9 years
    the canonical method of dealing with a changing array length is to start from the end of the array and work backwards. Alternatively it's possible to work forwards from the current position and not increment if you've removed the current element. Instead, your method starts over from the zeroth element every time a match is found, thereby repeatedly going over and over the same elements. It's a very poor algorithm and shouldn't ever be used.
  • Xotic750
    Xotic750 over 9 years
    And yet this ECMA5 method is super fast on the most current version of Chrome, and other browsers are bound to catch up, faster than the accepted answer on the small sample provided.
  • Alnitak
    Alnitak over 9 years
    If you had used the fromIndex parameter to .indexOf() I would have no complaint - that would make it O(n) instead of O(n^2). At the moment it only wins (on short arrays) because it's using a compiled built-in to scan the array instead of a hand-written loop. In fact if you had done this you'd actually have the best answer here.
  • Alnitak
    Alnitak over 9 years
    OK, that's weird - I tried that and (on this small sample set) it was substantially slower. I don't know why yet. jsperf.com/soq-iterate-over-an-array-and-remove/2
  • Xotic750
    Xotic750 over 9 years
    Personally, I would usually use the method shown in the accepted answer, and that is why I also voted for it. But interesting results.
  • Alnitak
    Alnitak over 9 years
    I changed the test case slightly - now the fromIndex case runs very slightly faster... jsperf.com/soq-iterate-over-an-array-and-remove/3
  • Xotic750
    Xotic750 over 9 years
    I guess (not tested) that it will make more of a difference on a larger set of data, and it is still only fastest on Chrome (with this small data set) and so using the reverse loop gives better cross browser performance. Feel free to improve my answer, if you feel like it. :)
  • HumanInDisguise
    HumanInDisguise almost 9 years
  • ingernet
    ingernet over 8 years
    i wish i could upvote this more than once. Occam is sending you a cosmic high five from the great beyond.
  • spikyjt
    spikyjt over 7 years
    As you say in your edit, this doesn't actually answer the question, however it does answer the question I was trying to search for. Thank you.
  • sktguha
    sktguha about 7 years
    personally I feel filter is safer as decrementing i may lead to edge cases as if zero elements are there etc
  • Nico Westerdale
    Nico Westerdale almost 7 years
    In terms of code readability this answer is lovely
  • PirateApp
    PirateApp over 6 years
    can this be done in a for of looP?
  • Don Hatch
    Don Hatch almost 5 years
    Downvoted for "I never made any claims on efficiency, and the question didn't concern that".
  • Don Hatch
    Don Hatch almost 5 years
    Seriously? An O(n^2) answer, with 147 upvotes and no downvotes? Here's a downvote for you.
  • Don Hatch
    Don Hatch almost 5 years
    @Alnitak, no, using the fromIndex parameter will not fix this algorithm's quadratic behavior.
  • Alnitak
    Alnitak almost 5 years
    @DonHatch Are you alluding to the removal operation itself being something other than O(1) ? The point of using fromIndex is that it prevents the scan from considering the entire array from the start each time.
  • Don Hatch
    Don Hatch almost 5 years
    @Alnitak, right, the removal isn't O(1).
  • Alnitak
    Alnitak almost 5 years
    @DonHatch well, it might be, but that's implementation dependent. If the removal is itself O(n) then the original algorithm here would be O(n^3)
  • Don Hatch
    Don Hatch almost 5 years
    @Alnitak, no, it's not implementation dependent; think about how many items the splice() has to move, in order to make them look-up-able in O(1) time afterwards. And no, that doesn't make the overall algorithm O(n^3); there are O(n) splices taking O(n) time, contributing O(n)*O(n) = O(n^2) to the overall time.
  • Xotic750
    Xotic750 almost 5 years
    @DonHatch So you downvoted the answer because of a comment? Ok, thanks. :D
  • Michael
    Michael over 4 years
    Now if you want to put the elements in a different array, you have to unshift instead of push to retain the correct order. not cool.
  • Tasik
    Tasik over 3 years
    Isn't this just O(n)? It only loops through the entire array once.
  • reducing activity
    reducing activity about 3 years
    @DonHatch Thanks for a warning, I would miss it!
  • reducing activity
    reducing activity about 3 years
    @Tasik What is O() complexity of splice? It seems to be O(N), so if code would remove say 1/4 of array, in front - it would need to make (1/4*N) * (3/4*N) = 3/16N^2 operations, giving N^2 But see stackoverflow.com/a/54879636/4130619 so...
  • Tasik
    Tasik almost 3 years
    @reducingactivity Right. That makes sense. Thank you.