How does this loop work to check duplicates?

Asked

Viewed 85 times

3

The code below creates another filtering array so there are no duplicate values:

var array = [1,1,1,2,3,4,4,5];
var models = [];

for ( var i = 0; i < array.length; i++ ) {
   if ( array.indexOf( array[ i ] ) === i ) {
      models.push(array[ i ] );
   }
}
console.log(models);

Upshot:

models = [1,2,3,4,5]

But I couldn’t understand how he does it in the excerpt:

array.indexOf( array[ i ] ) === i )

How it checks if it is duplicated through this stretch?

1 answer

7


According to the documentation, indexOf returns the first index that has the given element. Ex:

let array = [ 1, 2, 3, 1, 4];

console.log(array.indexOf(1)); // 0

The number 1 is in two positions of the array (at positions zero and 3 - remember that the first position is zero, the second is 1, etc.), but array.indexOf(1) returns 0, as it is the index corresponding to the first occurrence of 1 inside the array.

So array.indexOf( array[ i ] ) checks the first position in which the element occurs array[i] (that is, what is the first position in which the position element occurs i). If that position differs from i, means the element is duplicated.

Using our above array as an example: when i is equal to 3, array[i] number 1 (the second occurrence of number 1). Only array.indexOf( array[ i ] ), as we have seen, returns zero, which is different from 3, and so then I detected that the element is repeated.

So in fact the if detects the first occurrence of each element. If different, it does not enter the if, because then I know it’s duplicated and I don’t need to insert the element again in models.


From ES6, you can use a Set to obtain the same result:

let array = [1,1,1,2,3,4,4,5];

let models = Array.from(new Set(array));
console.log(models); // [1, 2, 3, 4, 5]

// ou usando spread syntax: https://developer.mozilla.org/pt-PT/docs/Web/JavaScript/Reference/Operators/Spread_syntax
models = [... new Set(array)];
console.log(models); // [1, 2, 3, 4, 5]


Finally, it is worth remembering that indexOf at all times checks the array from the first element, i.e., for each element of the array, I will be traversing the same array several times, from the beginning to the first occurrence of the element (a variation of the Shlemiel the Painter’s Algorithm).

So this algorithm can become very inefficient as the array increases (for small arrays it won’t make as much difference, but for larger arrays, it can be a problem, especially if it doesn’t have too many repeating elements).

Another approach would be to have an object to store the elements that have already been found:

let array = [1,1,1,2,3,4,4,5];
let models = [];
let encontrados = {};
for (var i = 0; i < array.length; i++) {
    // só adiciono quem ainda não foi encontrado
    if (encontrados[array[i]] === undefined){
       encontrados[array[i]] = true;
       models.push(array[i]);
    }
}
console.log(models);

Doing a basic test with an array of more than 10,000 elements, this approach proved much faster than the others. But for a small array, indexOf was faster.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.