Reputation: 991
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
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
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.
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.)
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
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