user2305363 user2305363 - 12 days ago 9
Javascript Question

How to remove objects from array when splice() reorders

I have an Javascript array of objects. I'm looping through the array with a forEach and checking for a specific match, and if that match is true, splicing/removing it from the array at the current index.

Am I mad?

When I find a match and splice/remove that object from the array, it seems like the array is automatically shifting, causing the next item to be skipped as the index is incremented. Is this true? If so, what is the most accurate way to loop and test each ALL of the objects in an array and delete ALL the matches?

Code example (mind you this is clearly not an array of objects, just a quick example):

var fruits = ["Banana", "Orange", "Apple", "Mango"]
document.getElementById("demo").innerHTML = fruits;

function myFunction() {
fruits.forEach(function(fruit, index) {
if(fruit == "Banana" || fruit == "Orange" ) {
fruits.splice(index, 1);
}
})
document.getElementById("demo").innerHTML = fruits;
}
myFunction();


RESULT:
Orange,Apple,Mango

In that example, Banana is removed, thus "shifting" Orange to 0. At this point, the index is then incremented to 1, skipping 0, or Orange altogether, and continuing through the loop.

The only solution I have at this point is replacing the deleted item with something in order to prevent the "shift".

Splice example

fruits.splice(index, 1, "deleted");


Result

deleted,deleted,Apple,Mango

My Question

Is this the best/most accurate way of deleting items/objects from an array by means of a loop?

Thank you for your time and advice.

Answer

In general, it's not a good idea to mutate the array that you are currently iterating through, for reasons you mentioned above. What your code is intending to do is a very common use-case called filter in Functional Programming. Read the docs on Array.prototype.filter. Pass the filter function the array and a predicate function to determine if the element is to be included in the filtered result. The filter function will make a copy of the original array without the unwanted elements.

Example code:

function myFunction() {
  var filteredFruits = fruits.filter(function(fruit) { 
    return fruit !== "Banana" && fruit !== "Orange";
  });
  // filteredFruits = ["Apple", "Mango"]
  document.getElementById("demo").innerHTML = filteredFruits;
}
myFunction();
Comments