Categories
arrays javascript unique

Get all unique values in a JavaScript array (remove duplicates)

2428

I have an array of numbers that I need to make sure are unique. I found the code snippet below on the internet and it works great until the array has a zero in it. I found this other script here on Stack Overflow that looks almost exactly like it, but it doesn’t fail.

So for the sake of helping me learn, can someone help me determine where the prototype script is going wrong?

Array.prototype.getUnique = function() {
 var o = {}, a = [], i, e;
 for (i = 0; e = this[i]; i++) {o[e] = 1};
 for (e in o) {a.push (e)};
 return a;
}

More answers from duplicate question:

Similar question:

10

  • 6

    @hippietrail That older question is about finding and returning only the duplicates (I was confused too!). My question is more about why this function fails when an array has a zero in it.

    – Mottie

    Feb 12, 2014 at 17:34

  • For future readers, when start finding that you have to algorithmically modify the contents of your data structure all the time, (order them, remove repeating elements, etc.) or search for elements inside it at every iteration, it’s safe to assume that you’re using the wrong data structure in the first place and start using one that is more appropriate for the task at hand (in this case a hash set instead of array).

    – nurettin

    Dec 30, 2014 at 11:16


  • I copied the code from somewhere else, a loooong time ago… but it seems pretty straight-forward: o = object, a = array, i = index and e = umm, something 😛

    – Mottie

    Aug 4, 2015 at 12:38

  • Possible duplicate of How to get unique values in an array

    Dec 25, 2017 at 19:36

  • Just wanted to point out, a lot of people have suggested using JavaScript Set as a solution, proceed with caution because it is not supported in Internet Explorer. If you have to support IE, then use a polyfill.

    – Nam Kim

    Nov 18, 2019 at 22:16

4073

With JavaScript 1.6 / ECMAScript 5 you can use the native filter method of an Array in the following way to get an array with unique values:

function onlyUnique(value, index, self) {
  return self.indexOf(value) === index;
}

// usage example:
var a = ['a', 1, 'a', 2, '1'];
var unique = a.filter(onlyUnique);

console.log(unique); // ['a', 1, 2, '1']

The native method filter will loop through the array and leave only those entries that pass the given callback function onlyUnique.

onlyUnique checks, if the given value is the first occurring. If not, it must be a duplicate and will not be copied.

This solution works without any extra library like jQuery or prototype.js.

It works for arrays with mixed value types too.

For old Browsers (<ie9), that do not support the native methods filter and indexOf you can find work arounds in the MDN documentation for filter and indexOf.

If you want to keep the last occurrence of a value, simply replace indexOf with lastIndexOf.

With ES6 this can be shorten to:

// usage example:
var myArray = ['a', 1, 'a', 2, '1'];
var unique = myArray.filter((v, i, a) => a.indexOf(v) === i);

console.log(unique); // unique is ['a', 1, 2, '1']

Thanks to Camilo Martin for hint in comment.

ES6 has a native object Set to store unique values. To get an array with unique values you could now do this:

var myArray = ['a', 1, 'a', 2, '1'];

let unique = [...new Set(myArray)];

console.log(unique); // unique is ['a', 1, 2, '1']

The constructor of Set takes an iterable object, like an Array, and the spread operator ... transform the set back into an Array. Thanks to Lukas Liese for hint in comment.

12

  • 93

    This solution will run much slower, unfortunately. You’re looping twice, once with filter and once with index of

    Nov 23, 2013 at 10:11


  • 44

    In modern JS: .filter((v,i,a)=>a.indexOf(v)==i) (fat arrow notation).

    Jul 24, 2016 at 8:43

  • 317

    let unique_values = [...new Set(random_array)]; developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…

    Nov 19, 2016 at 15:07

  • 1

    Why is [...] necessary? new Set(myArray) on its own seems to have the same behaviour

    – Chris A

    Jan 27 at 1:00

  • 8

    Lest any newcomer be scared away by the performance implications, consider “much slower” may very well be nanoseconds. If your array is relatively small (hundreds or less), using the nice concise one off version like this is good for reasons outside of performance, i.e. readability and maintainability. But the set version is quite nice and concise.

    Feb 15 at 21:31

1529

Updated answer for ES6/ES2015: Using the Set and the spread operator (thanks le-m), the single line solution is:

let uniqueItems = [...new Set(items)]

Which returns

[4, 5, 6, 3, 2, 23, 1]

4

  • 18

    Notice, that inner array wouldn’t work Array.from(new Set([[1,2],[1,2],[1,2,3]]))

    Oct 24, 2016 at 13:49

  • 95

    Please note that if you use the Set and add objects instead of primitive values it will contain unique references to the objects. Thus the set s in let s = new Set([{Foo:"Bar"}, {Foo:"Bar"}]); will return this: Set { { Foo: 'Bar' }, { Foo: 'Bar' } } which is a Set with unique object references to objects that contain the same values. If you write let o = {Foo:"Bar"}; and then create a set with two references like so: let s2 = new Set([o,o]);, then s2 will be Set { { Foo: 'Bar' } }

    – mortb

    Apr 5, 2017 at 9:14


  • 4

    In case anyone was wondering, this works well for strings too, e.g. […new Set([“apple”,”apple”,”orange”])] results in [‘apple’, ‘orange’] . Great!

    – Marquez

    Nov 24, 2021 at 19:07


  • In Typescript, use Array.from( new Set( items ) )

    May 23 at 9:24

291

I split all answers to 4 possible solutions:

  1. Use object { } to prevent duplicates
  2. Use helper array [ ]
  3. Use filter + indexOf
  4. Bonus! ES6 Sets method.

Here’s sample codes found in answers:

Use object { } to prevent duplicates

function uniqueArray1( ar ) {
  var j = {};

  ar.forEach( function(v) {
    j[v+ '::' + typeof v] = v;
  });

  return Object.keys(j).map(function(v){
    return j[v];
  });
} 

Use helper array [ ]

function uniqueArray2(arr) {
    var a = [];
    for (var i=0, l=arr.length; i<l; i++)
        if (a.indexOf(arr[i]) === -1 && arr[i] !== '')
            a.push(arr[i]);
    return a;
}

Use filter + indexOf

function uniqueArray3(a) {
  function onlyUnique(value, index, self) { 
      return self.indexOf(value) === index;
  }

  // usage
  var unique = a.filter( onlyUnique ); // returns ['a', 1, 2, '1']

  return unique;
}

Use ES6 [...new Set(a)]

function uniqueArray4(a) {
  return [...new Set(a)];
}

And I wondered which one is faster. I’ve made sample Google Sheet to test functions. Note: ECMA 6 is not avaliable in Google Sheets, so I can’t test it.

Here’s the result of tests:
enter image description here

I expected to see that code using object { } will win because it uses hash. So I’m glad that tests showed the best results for this algorithm in Chrome and IE. Thanks to @rab for the code.

Update 2020

Google Script enabled ES6 Engine. Now I tested the last code with Sets and it appeared faster than the object method.

2

  • 4

    Makrov, so the uniqueItems = [...new Set(items)] appears to be the fastest and the most succinct of all the approaches?

    – Vass

    Oct 29, 2021 at 18:45

  • Your solution only handles primitives, it won’t work with objects, you’d need to JSON.stringify the v in the hash

    – Tofandel

    May 4 at 12:30