0

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?

4
  • I'm confused. after your second filter the array already has no duplicates. (And the first filter is not needed.) Commented Jun 11, 2019 at 11:29
  • 2
    @ScottSauyet I think he wants to get rid of both the numbers that were duplicated. Which he could just do with arr.filter(x=> dup.indexOf(x) < 0). But he is trying to remove it with some convoluted looping Commented Jun 11, 2019 at 11:31
  • @James, oh ok, that makes sense. Commented Jun 11, 2019 at 11:33
  • @James your answer seems simple and easy. I will replace all my loops with that single line. Thanks Commented Jun 11, 2019 at 12:07

3 Answers 3

3

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)]
Sign up to request clarification or add additional context in comments.

3 Comments

this doesn't answer his question of why his IF is only hitting once.
fair point @James, hopefully this suggestion can be used by the OP if it gets the desired outcome. I am finding it hard to debug his actual code with the multiple while and if statements
Yeah it's confusing. I think he wants to get rid of the item that was duplicated too by the way, as he already has the unique items in his arr after the second filter. So in your example he'd just want [2]
3

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.

4 Comments

Can you tell me what type singletons is. What are the parenthesis for. And why xs, dups. Can you just tell me where to learn about it.
@EyePatch: I added an explanation section. Short version: this is a fairly standard functional programming approach.
I didn't realize it was a function 'cause there is an assignment inside the parenthesis. I didn't know such thing is possible.
@EyePatch: Default Parameters can be very useful for this sort of thing.
2

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)

3 Comments

Yeah. Actually I tried at first whit for loops but It was kind of the same problem so I switched to while lopps hoping it would fix it.
The advantage here is that you don't need to define the variables you are going through, it's all handled. Probably the shortest and most solid approach. While-loops are tricky, sometimes they don't terminate as you might expect, or in your case, cycle.
it worked fine. but to solve my problem with removing both duplicates in my array I prefered the answer in the comment to my question which a single line code

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.