0

I have an array with functions/Objects in it. This Objects have a function to test itself and if they fail they get removed from the array. If I run a forEach on this array and run this testfunction and one object gets removed from the array the forEach loop skips an object.

What is a good way to solve this problem?

Here a example. Run the example and you will see the the 2ed Object tests.push(new Test(2)); is skipped in the forEach loop.

//creating a test array
var tests = [];
tests.push(new Test(1));
tests.push(new Test(2));
tests.push(new Test(3));
tests.push(new Test(4));

function Test(n) {
  this.n = n;

  this.testme = function() {
    if(this.n < 3) {
   tests.splice(tests.indexOf(this), 1); //remove me from the array tests please!
   console.log(this.n, "I got removed!");
    } else {
      console.log(this.n, "I can stay!");
    }
  } 
}


console.log("tests length: ", tests.length);

tests.forEach(function(t) {
  t.testme();
});

console.log("tests length: ", tests.length); //output should now be 2 
nbar
  • 6,028
  • 2
  • 24
  • 65
  • 1
    Have you tried https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/filter? – jmargolisvt Jul 12 '19 at 17:51
  • @jmargolisvt oh that would be perfect for my example. However in my real project the call needs to come from inside the Object. So in theory I could run the `testme`function and if the test fails set a flag, for example `this.remove = 1`. After that I use the filter function and filter for that flag. This would work. I wonder, is this an efficient method? – nbar Jul 12 '19 at 17:55
  • 1
    Possible duplicate of [Looping through array and removing items, without breaking for loop](https://stackoverflow.com/questions/9882284/looping-through-array-and-removing-items-without-breaking-for-loop), [How to iterate over an array and remove elements in JavaScript](https://stackoverflow.com/questions/16352546/how-to-iterate-over-an-array-and-remove-elements-in-javascript), [How to remove element from array in forEach loop?](https://stackoverflow.com/questions/24812930/how-to-remove-element-from-array-in-foreach-loop). Surprised to see such support for the answers on this one to be honest. – Tyler Roper Jul 12 '19 at 18:01

2 Answers2

3

why not use the built in filter function?

tests = tests.filter(t => t.testMe());
ThS
  • 4,597
  • 2
  • 15
  • 27
bryan60
  • 28,215
  • 4
  • 48
  • 65
  • This will require modifying the existing `testme` function – Get Off My Lawn Jul 12 '19 at 18:00
  • For my real project I am not able to use the return value, but I would be able to set a flag (see my answer to jmargolisvts commet). I wonder, which one is more efficient. using the filter method on the array after I am done with the forEach loop, or use splice, but use the trick from GetOfMyLawns answer (loop backwards over the array) and then use splice in the array. – nbar Jul 12 '19 at 18:01
  • yea but it'd be simpler, just `return this.n >= 3)` – bryan60 Jul 12 '19 at 18:01
  • Yeah, my comment is just a note, without modification, the end result is `0` in my test. – Get Off My Lawn Jul 12 '19 at 18:03
2

What you will want to do is loop over the array in reverse:

let i = tests.length
while(i--) tests[i].testme()

Here it is in action:

//creating a test array
var tests = [];
tests.push(new Test(1));
tests.push(new Test(2));
tests.push(new Test(3));
tests.push(new Test(4));

function Test(n) {
  this.n = n;

  this.testme = function() {
    if(this.n < 3) {
   tests.splice(tests.indexOf(this), 1); //remove me from the array tests please!
   console.log(this.n, "I got removed!");
    } else {
      console.log(this.n, "I can stay!");
    }
  } 
}


console.log("tests length: ", tests.length);

let i = tests.length
while(i--) tests[i].testme()

console.log("tests length: ", tests.length); //output should now be 2
Get Off My Lawn
  • 34,175
  • 38
  • 176
  • 338