1

I want to use splice() with a 'for...of' loop.

Here is what I want to do but with a regular 'for' loop:

let celebritiesResult = JSON.parse(celebrityRecognitionJSONFile);
let celebritiesMap = {}
const timestampTolerance = 1000;
const confidenceTolerance = 90;
for (let j = 0; j < celebritiesResult.length;) {
    let celebrity = celebritiesResult[j];
    let prevCelebrity = celebritiesMap[celebrity.Celebrity.Name];
    if ((!prevCelebrity || celebrity.Timestamp - prevCelebrity.Timestamp > timestampTolerance) && celebrity.Celebrity.Confidence > confidenceTolerance) {
        celebritiesMap[celebrity.Celebrity.Name] = celebrity;
        j++;
    } else {
        celebritiesResult.splice(j, 1);
    }
}

When I do the same using a 'for...of' loop:

let celebritiesResult = JSON.parse(celebrityRecognitionJSONFile);
let celebritiesMap = {}
const timestampTolerance = 1000;
const confidenceTolerance = 90;
let count = 0;
for (let celebrity of celebritiesResult) {
    let prevCelebrity = celebritiesMap[celebrity.Celebrity.Name];
    if ((!prevCelebrity || celebrity.Timestamp - prevCelebrity.Timestamp > timestampTolerance) && celebrity.Celebrity.Confidence > confidenceTolerance) {
        celebritiesMap[celebrity.Celebrity.Name] = celebrity;
        count++;
    } else {
        celebritiesResult.splice(count, 1);
    }
}

It doesn't work as expected, the 'splice()' function doesn't remove all elements expected to be removed.

I managed to make the 'for...of' loop work, by creating a second object 'celebritiesResult2' as a clone of 'celebritiesResult' and applying the 'splice()' (method on it):

let celebritiesResult = JSON.parse(celebrityRecognitionJSONFile);
let celebritiesResult2 = JSON.parse(celebrityRecognitionJSONFile);//<-
let celebritiesMap = {}
const timestampTolerance = 1000;
const confidenceTolerance = 90;
let count = 0;
for (let celebrity of celebritiesResult) {
    let prevCelebrity = celebritiesMap[celebrity.Celebrity.Name];
    if ((!prevCelebrity || celebrity.Timestamp - prevCelebrity.Timestamp > timestampTolerance) && celebrity.Celebrity.Confidence > confidenceTolerance) {
        celebritiesMap[celebrity.Celebrity.Name] = celebrity;
        count++;
    } else {
        **celebritiesResult2.splice(count, 1);//<-
    }
}

The same happens with 'foreach()' too. I have also to create a second object and apply the 'splice()' method on it, so it works as expected.

let celebritiesResult = JSON.parse(celebrityRecognitionJSONFile);
let celebritiesResult2 = JSON.parse(celebrityRecognitionJSONFile);//<-
let celebritiesMap = {};
const timestampTolerance = 1000;
const confidenceTolerance = 90;
celebritiesResult.forEach((item, index) => {
    let celebrity = item;
    let prevCelebrity = celebritiesMap[celebrity.Celebrity.Name];
    if ((!prevCelebrity || celebrity.Timestamp - prevCelebrity.Timestamp > timestampTolerance) && celebrity.Celebrity.Confidence > confidenceTolerance) {
        celebritiesMap[celebrity.Celebrity.Name] = celebrity;
    } else {
        celebritiesResult2.splice(index, 1);//<-
    }
});

Why?


EDIT


What I don't understand actually, is why the regular for loop works and other don't! If we consider what is explained in the link marked as duplicate (Looping through array and removing items, without breaking for loop), the for loop should be wrong to, and it's not. Why I cannot do the same with a for...of loop!?!?!?

Kr1
  • 1,269
  • 2
  • 24
  • 56
  • 3
    Why do you want to use `for..of`? If it works with an indexed for loop, use an indexed for loop. Basically, you're mutating the array you're iterating over, which leads to exactly these kinds of problems. – Heretic Monkey Sep 02 '19 at 13:12
  • @HereticMonkey, I prefer the `for...of`syntax. I just want to understand to avoid similar issues in further developments. The regular `for` loop has been created by another guy, and I had the feeling it was not accurate, so I wanted to verify it by doing the same stuff in my own way. – Kr1 Sep 02 '19 at 13:47

1 Answers1

1

None of your examples will work correctly, including for in loop, because you are modifying number of items in the array, while iterating. Look at the result of simplified for-in example:

let array  = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
for (let j = 0; j < array.length;j++) {
 if (j % 2 === 0) {
   array.splice(j, 1);
  }
}
console.log(array);

Cleanest approach is, instead of modifying source array, to create new result:

let array  = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

let result = array.filter((item, index) => {
 return index % 2 === 0 ? false : true;
});
console.log(result);
Nenad
  • 24,809
  • 11
  • 75
  • 93
  • In the third and forth example, I am not modifying the same array used for the loop. Are you sure they are not working as expected? – Kr1 Sep 02 '19 at 13:45
  • These are almost identical to answers in the proposed duplicate... – Heretic Monkey Sep 02 '19 at 13:51
  • @118218 I understood you implied that your `for-in` loop works, but `for-of` does not, while neither of those 2 works. Examples with copy (3rd and 4th) probably work, but then you don't need all the extra logic, when you can just filter then. – Nenad Sep 02 '19 at 14:15
  • @HereticMonkey I have looked at proposed duplicate now. There is one answer with `filter` at 5th place. I think this answer is more tailored to what was asked here. It is also more general (no `Auctions.auctions.filter...`) and runnable with clear result. – Nenad Sep 02 '19 at 14:19