10

I have an array here:

var myArr = [1, 1, 2, 5, 5, 7, 8, 9, 9];

Now I want to remove both appearances of a duplicate. So the desired result is not:

var myArr = [1, 2, 5, 7, 8 ,9];

but

var myArr = [2, 7, 8];

Basically I know how to remove duplicates, but not in that that special way. Thats why any help would be really appreciated!

Please note: My array is filled with strings. The numbers here were only used as an example.

Sven
  • 12,129
  • 25
  • 82
  • 140

9 Answers9

2

Wherever removing duplicates is involved, it's not a bad idea to use a set data structure.

JavaScript doesn't have a native set implementation, but the keys of an object work just as well - and in this case help because then the values can be used to keep track of how often an item appeared in the array:

function removeDuplicates(arr) {
    var counts = arr.reduce(function(counts, item) {
        counts[item] = (counts[item]||0)+1;
        return counts;
    }, {});
    return Object.keys(counts).reduce(function(arr, item) {
        if(counts[item] === 1) {
            arr.push(item);
        }
        return arr;
    }, []);
}

var myArr = [1, 1, 2, 5, 5, 7, 8, 9, 9];
removeDuplicates(myArr);

Check out the example on jsfiddle.

Alternately, you could not use calls to reduce(), and instead use for and for(item in counts) loops:

function removeDuplicates(arr) {
    var counts = {};
    for(var i=0; i<arr.length; i++) {
        var item = arr[i];
        counts[item] = (counts[item]||0)+1;
    }
    var arr = [];
    for(item in counts) {
        if(counts[item] === 1) {
            arr.push(item);
        }
    }
    return arr;
}

Check out the example on jsfiddle.

Richard JP Le Guen
  • 26,771
  • 7
  • 80
  • 113
1

EDITED with better answer:

var myArr = [1, 1, 2, 5, 5, 7, 8, 9, 9];

function removeDuplicates(arr) {
    var i, tmp;
    for(i=0; i<arr.length; i++) {
        tmp = arr.lastIndexOf(arr[i]);
        if(tmp === i) {
            //Only one of this number
        } else {
            //More than one
            arr.splice(tmp, 1);
            arr.splice(i, 1);
        }
    }
}
Joel Fischer
  • 6,351
  • 5
  • 33
  • 45
  • I was going to post an answer using this strategy. Here's is the jsFiddle I had written to help: http://jsfiddle.net/VBYun/ – Jesse Jul 13 '12 at 16:34
  • At the end, myArr contains `[1, 5, 7, 9] `. – j08691 Jul 13 '12 at 16:34
  • Ugh, I just realized this will only work if there are only 2 of the numbers in the array. If that's the max, there's a much easier way of checking the lastIndexOf() against the current i value. If they match, you're good, if they don't you can delete both based on the index you have for each. – Joel Fischer Jul 13 '12 at 16:35
  • 1
    var myArr = [1, 1, 2, 5, 5, 7, 8, 9, 9]; function removeDuplicates(arr) { var i, tmp; for(i=0; i – Joel Fischer Jul 13 '12 at 16:39
  • I like this answer... but I don't think it works if the elements aren't in order: http://jsfiddle.net/vBcmp/ – Richard JP Le Guen Jul 14 '12 at 21:30
  • ... and the OP already established that the array is "[filled with strings, not ordered](http://stackoverflow.com/questions/11474422/deleting-both-values-from-array-if-duplicate-javascript-jquery/11474617#comment-15150640)" – Richard JP Le Guen Jul 14 '12 at 21:31
1

jsfiddle for this code:

var myArr = [1, 1, 2, 5, 5, 7, 8, 9, 9];
var newArr = myArr;
var h,i,j;


for(h = 0; h < myArr.length; h++) {
    var curItem = myArr[h];
    var foundCount = 0;
    // search array for item
    for(i = 0; i < myArr.length; i++) {
        if (myArr[i] == myArr[h])
            foundCount++;
    }
    if(foundCount > 1) {
        // remove repeated item from new array
        for(j = 0; j < newArr.length; j++) {
            if(newArr[j] == curItem) {                
                newArr.splice(j, 1);
                j--;
            }
        }            
    }
}
BumbleB2na
  • 10,522
  • 6
  • 24
  • 30
1

Here's my version

var a = [1, 1, 2, 5, 5, 7, 8, 9, 9];

function removeIfduplicate( arr ) {
    var discarded = [];
    var good      = [];
    var test;
    while( test = arr.pop() ) {
        if( arr.indexOf( test ) > -1 ) {
            discarded.push( test );
            continue;
        } else if( discarded.indexOf( test ) == -1 ) {
            good.push( test );
        }
    }
    return good.reverse();
}

x = removeIfduplicate( a );
console.log( x ); //[2, 7, 8]
meouw
  • 40,162
  • 10
  • 48
  • 67
0

If it's just alphanumeric, duplicates are case-sensitive, and there can be no more than two of any element, then something like this can work:

var a = [2, 1, "a", 3, 2, "A", "b", 5, 6, 6, "B", "a"],

    clean_array = $.map(a.sort(), function (v,i) {
        a[i] === a[i+1] && (a[i] = a[i+1] = null);
        return a[i];
    });

// clean_array = [1,3,5,"A","B","b"]
Richard Neil Ilagan
  • 14,133
  • 5
  • 44
  • 64
0

In this example,we are taking two arrays as function arguments, from this we are going to print only unique values of both arrays hence deleting the values that are present in both arrays.

first i am concatenating both the arrays into one. Then I taking each array value at a time and looping over the array itself searching for its no of occurrence. if no of occurrence(i.e.,count) equal to 1 then we are pushing that element into the result array. Then we can return the result array.

function diffArray(arr1, arr2) {
  var newArr = [];
  var myArr=arr1.concat(arr2);
  var count=0;
  for(i=0;i<myArr.length;i++){
    for(j=0;j<myArr.length;j++){
      if(myArr[j]==myArr[i]){
        count++;
      }
    }
    if(count==1){
      newArr.push(myArr[i]);
    }
    count=0;
  }
  return newArr;
}
0

Heres a short version using Array.filter(). The trick is to first find all values that are NOT uniqe, and then use this array to reject all unique items in the original array.

let myArr = [1, 1, 2, 5, 5, 7, 8, 9, 9];
let duplicateValues = myArr.filter((item, indx, s) => s.indexOf(item) !== indx);
myArr.filter(item => !duplicateValues.includes(item));
// => [2, 7, 8]



(If you're interested in the Explenation)

// this statement removes all dupicate values
myArr.filter((item, indx, s) => s.indexOf(item) === indx)

// by changing === to !== we do the "opposite", which means that we remove
// all items that are unique
myArr.filter((item, indx, s) => s.indexOf(item) !== indx)

thomas
  • 429
  • 4
  • 17
-1

EDIT: Here is the jspref http://jsperf.com/deleting-both-values-from-array

http://jsfiddle.net/3u7FK/1/

This is the fastest way to do it in two passes without using any fancy tricks and keeping it flexible. You first spin through and find the count of every occurance and put it into and keyvalue pair. Then spin through it again and filter out the ones where the count was greater than 1. This also has the advanatage of being able to apply other filters than just "greater than 1"; as well as the having the count of occurances if you needed that as well for something else.

This should work with strings as well instead of numbers.

http://jsfiddle.net/mvBY4/1/

var myArr = [1, 1, 2, 5, 5, 7, 8, 9, 9];
var map = new Object();

for(var i = 0; i < myArr.length; i++)
{
    if(map[myArr[i]] === undefined)
    {
        map[myArr[i]] = 1;
    }
    else
    {
        map[myArr[i]]++;
    }
}

var result = new Array();

for(var i = 0; i < myArr.length; i++)
{   
    if(map[myArr[i]] > 1)
    {
        //do nothing
    }
    else
    {
        result.push(myArr[i]);
    }

}

alert(result);
Murtnowski
  • 2,441
  • 1
  • 16
  • 34
  • If performance and speed is what you're going for, the second loop iterates more often than it has to. Like @Alnitak suggested, you should use a `for(key in map) { /*...*/ }` loop – Richard JP Le Guen Jul 14 '12 at 21:45
-1

You can use Set (available in IE 11+) as below

const sourceArray = [1, 2, 3, 4, 5, 5, 6, 6, 7, 7, 8];
const duplicatesRemoved = new Set();

sourceArray.forEach(element => {
    if (duplicatesRemoved.has(element)) {
        duplicatesRemoved.delete(element)
    } else {
        duplicatesRemoved.add(element)
    }
})

console.log(Array.from(duplicatesRemoved))

N.B. Arrow functions are not supported in older browsers. Use normal function syntax for that instead. However, Array.from can easily be polyfilled for older browsers.

Try it here.

Ozil
  • 877
  • 3
  • 11
  • 27