Eye Patch
Eye Patch

Reputation: 991

Why if statements blocks in while loop?

I have an array of numbers with a bunch of duplicates. I need to get rid of them so I put the code:

  let dup = arr.filter((elem, pos)=> arr.indexOf(elem) !== pos);
  // dup Array contains the duplicate numbers
  arr = arr.filter((elem, pos)=> arr.indexOf(elem) == pos);
  //arr contains the whole array with duplicates
  let i = 0;
  let j = 0;
  while(i<arr.length){
    while(j<dup.length){
      if(arr[i] == dup[j]){
        arr.splice(i, 1);
        //the splice method resets the decrease the index of the array so
        i--;
      };
      j++;
    };
    i++
  }

The problem is that the if doesn't run after the first match.So the array splice the first duplicate that it finds and stops. How can I fix that?

Upvotes: 0

Views: 69

Answers (3)

jackik
jackik

Reputation: 93

You need to set j=0 inside the first while loop, otherwise, it will only run through the second while loop once.

Also, if I were you, I would use a for-loop (array.forEach() specifically) instead of while, because they already count the number of elements anyway.

My solution for this is this:

arr.forEach((e, i) => {
    dup.forEach((f, j) => {
        if(e==f){
            arr.splice(i, 1);
        }
    })
});

Hope it works for you.

EDIT:

Stolen from the comment from James to the original question. Javascript already provides an easy method to do just that anyway:

arr.filter(x=> dup.indexOf(x) < 0)

Upvotes: 2

Scott Sauyet
Scott Sauyet

Reputation: 50797

The problem is that you never reset j. You need to move that inside the while (i ...) loop.

let arr = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
console.log('arr', arr)

let dup = arr.filter((elem, pos)=> arr.indexOf(elem) !== pos);

console.log('dup', dup)

arr = arr.filter((elem, pos)=> arr.indexOf(elem) == pos)
console.log('new arr', arr)


let i = 0;
while(i<arr.length){
  let j = 0;
  while(j<dup.length){
    if(arr[i] == dup[j]){
      arr.splice(i, 1);
      i--;
    };
    j++;
  };
  i++
}

console.log('final arr', arr)

But there are easier ways to do this.

Update

I got pinged for mentioning easier ways without showing one. Here is an alternative way to get the same results:

const singletons = (
  xs,
  dups = xs .filter ((x, i) => arr .indexOf (x) !== i)
) => xs .filter (x => dups .indexOf (x) < 0)

let arr = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]

console .log (
  singletons (arr)
)

This version does not modify your original array, just returning a new one containing only the singleton elements (those that appear just once in the original list.)

Explanation

singletons is a function taking an array of some type of element and returning another array of the same type. Because that type is not specific, I use a non-specific name; a fairly strong convention make this xs. with the s noting that it's plural (i.e. an array of them.)

dups is an array of elements that is duplicated in your original. Although I include it as a defaulted parameter, we could just as easily have created it in the body of the function like this:

const singletons = (xs) => {
  const dups = xs .filter ((x, i) => arr .indexOf (x) !== i)
  return xs .filter (x => dups .indexOf (x) < 0)
}

The only reason I didn't was that I am perhaps over-fond of single expression bodies, thus avoiding the {-} pair and the return statement. But there is no real difference between these two approaches, except that the one I presented happens to do some additional work that I would never count on: if you supply a second parameter, an array of values, then, rather than removing the duplicates, it removes all those element from your array that are also in the second one, vaguely reminiscent of a set difference function.

The main advantage of this over your approach is that it is non-destructive. It does not mutate your original data. It also has no assignments, except in the default parameter, so there is no confusion in state management. ("Where do I put let j == 0?" is not a meaningful question here.) This makes it feel more robust.

Upvotes: 3

ak85
ak85

Reputation: 4264

From Get all unique values in a JavaScript array (remove duplicates)

const myArray = ['a', 1, 'a', 2, '1'];

const unique = [...new Set(myArray)]; 

// output ["a", 1, 2, "1"]

or as a function

const unique = [...new Set(myArray)]

Upvotes: 3

Related Questions