'Deleting both values from array if duplicate - JavaScript/jQuery

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.



Solution 1:[1]

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.

Solution 2:[2]

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]

Solution 3:[3]

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);
        }
    }
}

Solution 4:[4]

Using Hashmap

  1. create hashmap and count occurencies
  2. filter where hashmap.get(value) === 1 (only unique values)
const myArray = [1, 1, 2, 5, 5, 7, 8, 9, 9];
const map = new Map();
myArray.forEach(v => map.set(v, map.has(v) ? map.get(v)+1 : 1));
myArray.filter(v => map.get(v) === 1);

Old version (slower but valid too)

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]

Solution 5:[5]

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"]

Solution 6:[6]

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;
}

Solution 7:[7]

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);

Solution 8:[8]

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.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 meouw
Solution 3
Solution 4
Solution 5 Richard Neil Ilagan
Solution 6
Solution 7
Solution 8 Ozil