Tell me more ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

This question already has an answer here:

This seems like such a simple need but I've spent an inordinate amount of time trying to do this to no avail. I've looked at other questions on SO and I haven't found what I need. I have a very simple JavaScript array such as peoplenames = new Array("Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"); that may or may not contain duplicates and I need to simply remove the duplicates and put the unique values in a new array. That's it. I could point to all the codes that I've tried but I think it's useless because they don't work. If anyone has done this and can help me out I'd really appreciate it. JavaScript or jQuery solutions are both acceptable.

share|improve this question
I'm not a javascript programmer, but couldn't you just sort the array with a lexical comparator: javascriptkit.com/javatutors/arraysort.shtml and then loop through checking if each element is the same as the next and if so, removing it? – Benj Feb 10 '12 at 14:58
an advice, to create new array : peoplenames = ["Mike",...]; – mgraph Feb 10 '12 at 15:01

marked as duplicate by Felix Kling, Łukasz Lech, pilsetnieks, James Donnelly, syb0rg May 25 at 15:46

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

15 Answers

up vote 45 down vote accepted

Quick and dirty using jQuery:

var names = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"];
var uniqueNames = [];
$.each(names, function(i, el){
    if($.inArray(el, uniqueNames) === -1) uniqueNames.push(el);
});
share|improve this answer
this is clean and simple and has better cross-browser support – kramden88 Feb 16 '12 at 16:22
Works great. In case anyone has my issue... a mix of strings and numbers are not matched. So ["1", 1, 2, 3, "3"] will not work. Obviously. – nicaou Nov 21 '12 at 13:08
In that case, just make sure you "feed" the array only integers or numbers. parseInt() and toString() come to mind. ;-) – Ace Apr 3 at 15:24

You can always try putting it into an object, and then iterating through its keys:

a = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"];
b = {};
for (var i = 0; i < a.length; i++) {
    b[a[i]] = a[i];
}
c = [];
for (var key in b) {
    c.push(key);
}
//c:
//["Mike", "Matt", "Nancy", "Adam", "Jenny", "Carl"]
share|improve this answer

Less code than you might think.

uniqueArray = myArray.filter(function(elem, pos) {
    return myArray.indexOf(elem) == pos;
})

or, using the 3rd ("this array") parameter of the filter callback:

uniqueArray = myArray.filter(function(elem, pos, self) {
    return self.indexOf(elem) == pos;
})

A word of warning: filter and indexOf are (relatively) recent additions to Javascript and don't work in ancient browsers. See here for details.

A more realistic version that tries to use hash lookups when possible:

uniq = function(ary) {
    var prim = {"boolean":{}, "number":{}, "string":{}}, obj = [];

    return ary.filter(function(x) {
        var t = typeof x;
        return (t in prim) ? 
            !prim[t][x] && (prim[t][x] = 1) :
            obj.indexOf(x) < 0 && obj.push(x);
    });
}

a = ["a", null, 12, window, window.undef1, "b", window, 12, "12", window.undef2, null]
console.log(uniq(a)) // ["a", null, 12, DOMWindow, undefined, "b", "12"]

This will be linear for arrays of primitives, but still quadratic for objects.

share|improve this answer
6  
wow very elegant – kramden88 Feb 10 '12 at 15:09
5  
filter and indexOf have been introduced in ECMAScript 5, so this will not work in old IE versions (<9). If you care about those browsers, you will have to use libraries with similar functions (jQuery, underscore.js etc.) – Roman Bataev Feb 10 '12 at 15:26
4  
This is the only answer worth reading. I dont see why we need a 30kb library to solve a 3 line problem. – Roderick Obrist Nov 13 '12 at 6:09
2  
@RoderickObrist you might if you want your page to work in older browsers – Michael Robinson Dec 17 '12 at 2:25
6  
This is O(n^2) solution, which can run very slow in large arrays... – seriyPS Feb 3 at 0:47
show 4 more comments

You could also use the Array.unique() method from the JavaScript Lab library – or steal an idea from there.

However, the code there isn’t very well written, since it declares the unique() method as a property of the Array prototype, thus adding it to every Array, breaking the for...in functionality (because a for...in loop will always iterate over the unique variable, too).

share|improve this answer

Use Underscore.js

It's a library with a host of functions for manipulating arrays.

It's the tie to go along with jQuery's tux, and Backbone.js's suspenders.

_.uniq

_.uniq(array, [isSorted], [iterator]) Alias: unique
Produces a duplicate-free version of the array, using === to test object equality. If you know in advance that the array is sorted, passing true for isSorted will run a much faster algorithm. If you want to compute unique items based on a transformation, pass an iterator function.

Example

var names = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"];

alert(_.uniq(names, false));

NOTE: I realize this is an old post, but I thought this answer could add some value.

share|improve this answer
Array.prototype.remove = function(value) {
    var index = null;

    while ((index = this.indexOf(this)) !== -1)
        this.splice(index, 1);

    return this;
};
share|improve this answer

The following is more than 80% faster than the jQuery method listed (see tests below). It is an answer from a similar question a few years ago, if I come across the person who originally proposed it I will post credit. Pure JS.

var temp = {};
  for (var i = 0; i < array.length; i++)
  temp[array[i]] = true;
  var r = [];
  for (var k in temp)
  r.push(k);
  return r;

My Test Case comparison: http://jsperf.com/remove-duplicate-array-tests

share|improve this answer
1  
I add a more fast version in revision 4. Please, review! – seriyPS Feb 3 at 0:46
Works great. Thanks. – Jon May 9 at 22:32

Here is another approach using jQuery,

function uniqueArray(array){
  if ($.isArray(array)){
    var dupes = {}; var len, i;
    for (i=0,len=array.length;i<len;i++){
      var test = array[i].toString();
      if (dupes[test]) { array.splice(i,1); len--; i--; } else { dupes[test] = true; }
    }
  } 
  else {
    if (window.console) console.log('Not passing an array to uniqueArray, returning whatever you sent it - not filtered!');
      return(array);
  }
  return(array);
}

Author: William Skidmore

share|improve this answer
function removeDuplicates(inputArray) {
            var outputArray=new Array();

            if(inputArray.length>0){
                jQuery.each(inputArray, function(index, value) {
                    if(jQuery.inArray(value, outputArray) == -1){
                        outputArray.push(value);
                    }
                });
            }           
            return outputArray;
        }
share|improve this answer

The top answers have complexity of O(n²), but this can be done with just O(n) by using an object as a hash:

function getDistinctArray(arr) {
    var dups = {};
    return arr.filter(function(el) {
        var hash = el.valueOf();
        var isDup = dups[hash];
        dups[hash] = true;
        return !isDup;
    });
}

This will work for strings, numbers, and dates. If your array contains complex objects (ie, they have to be compared with ===), the above solution won't work. You can get an O(n) implementation for objects by setting a flag on the object itself:

function getDistinctObjArray(arr) {
    var distinctArr = arr.filter(function(el) {
        var isDup = el.inArray;
        el.inArray = true;
        return !isDup;
    });
    distinctArr.forEach(function(el) {
        delete el.inArray;
    });
    return distinctArr;
}
share|improve this answer

A single line version using array filter and indexOf functions:

arr = arr.filter (function (v, i, a) { return a.indexOf (v) == i });
share|improve this answer

If you don't want to include a whole library, you can use this one off to add a method that any array can use:

Array.prototype.uniq = function uniq() {
  return this.reduce(function(accum, cur) { 
    if (accum.indexOf(cur) === -1) accum.push(cur); 
    return accum; 
  }, [] );
}

["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"].uniq()
share|improve this answer

If you're creating the array yourself, you can save yourself a loop and the extra unique filter by doing the check as you're inserting the data;

var values = [];
$.each(collection, function() {
    var x = $(this).value;
    if (!$.inArray(x, values)) {
        values.push(x);
    }
});
share|improve this answer

Got tired of seeing all bad examples with for-loops or jQuery. Javascript has the perfect tools for this nowadays: sort, map and reduce.

Uniq reduce while keeping existing order

var names = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"];

var uniq = names.reduce(function(a,b){
    if (a.indexOf(b) < 0 ) a.push(b);
    return a;
  },[]);

console.log(uniq, names) // [ 'Mike', 'Matt', 'Nancy', 'Adam', 'Jenny', 'Carl' ]

// one liner
return names.reduce(function(a,b){if(a.indexOf(b)<0)a.push(b);return a;},[]);

Faster uniq with sorting

There are probably faster ways but this one is pretty decent.

var uniq = names.slice() // slice makes copy of array before sorting it
  .sort(function(a,b){
    return a - b;
  })
  .reduce(function(a,b){
    if (a.slice(-1) != b) a.push(b); // slice(-1) means last item in array without removing it (like .pop())
    return a;
  },[]); // this empty array becomes the starting value for a

// one liner
return names.slice().sort(function(a,b){return a - b}).reduce(function(a,b){if (a.slice(-1) != b) a.push(b);return a;},[]);
share|improve this answer

A slight modification of thg435's excellent answer to use a custom comparator:

function contains(array,obj) {
    for(var i =0;i<array.length;i++) {
        if(isEqual(array[i],obj))return true;
    }
    return false;
}
//comparator
function isEqual(obj1,obj2) {
    if(obj1.name==obj2.name) return true;
    return false;
}
function removeDuplicates(ary) {
    var arr = [];
    return ary.filter(function(x) {
        return !contains(arr,x) && arr.push(x);
    });
}
share|improve this answer

Not the answer you're looking for? Browse other questions tagged or ask your own question.