How to get unique values in a Javascript array?

Asked

Viewed 7,015 times

31

In PHP, when I have one array with duplicated values, it is possible to obtain only unique values through the function array_unique.

Example:

$array = ['a', 'b', 'b', 'c', 'c'];

array_unique($array); // ['a', 'b', 'c']

But I needed to do something similar in Javascript, but I couldn’t find a function that did it natively.

What is the simplest way in Javascript to get the unique values of a array?

I’m gonna leave this array for example:

var array = ['a', 'b', 'b', 'c', 'c'];

console.log(array);

6 answers

29


The solution that can be adopted now in JS (unless you need to work with older versions) is much simpler and better:

var array = ['a', 'b', 'b', 'c', 'c'];
var unique = [...new Set(array)];
console.log(unique);

Note that this only works well because everything is string, with different values may not turn out as waiting.

If you need to use another solution and wait for one array bigger will be more interesting to make a set as if it were an object, that is, use the values as keys, so there will be no repetition and will keep a good performance, but a little worse. Something like this:

var array = ['a', 'b', 'b', 'c', 'c'];
var unique = array.reduce((acc, curr) => (acc[curr] = '', acc), {});
console.log(Object.keys(unique));

The solution below was the easiest at the time, but has the problem reported by Luiz Felipe in comment, so it is not usually a good idea.


The solution I like best is to create a function to use together with filter() which is used precisely to determine which elements should be considered in an evaluation. She uses a functional programming style where it matters what she does and not how she does it.

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

var array = ['a', 'b', 'b', 'c', 'c'];
var unique = array.filter(unique);
console.log(unique);

Source.

I put in the Github for future reference.

filter() is a function that sweeps all elements of the array and sends to a function of callback defined by the programmer. In this function makes a comparison if it is the first occurrence of the value and only if it is filter() will consider as part of the new array.

The indexOf() gives the position of the first occurrence. If it matches the current index of the searched element, it is a value that matters in the adopted criterion. If not hitting means that it is already at least a second occurrence of that value, what does not matter.

This should work on most browsers currently used, only it doesn’t work on those that are already considered too old.

  • 2

    Succinct, efficient and easy to interpret +1. D

  • 1

    There’s an algorithm problem, on account of indexOf if you pass [NaN] the value NaN is lost in the filter, since the indexOf has a problem where NaN always returns -1.

  • 1

    @Gabrielkatakura is, may have this problem that needs to be dealt with. There may be others, in JS it is not easy to close all cases without treating a lot of exception. I believe it is a good caveat for all posted algorithms that use similar technique or have their own deficiencies.

  • 2

    @bigown 90% of the algorithms I see of an implementation unique have this problem in JS, this is normal, since the indexOf falls into the classic prank of NaN !== NaN

  • 1

    I think it’s worth pointing out that as much filter how much indexOf are linear, this code is executed in quadratic time, which nay is efficient for cases where the number of elements is already becoming expressive. The difference is quite striking.

  • @Luizfelipe gave an improved.

  • Good! I will enjoy and link this other question, q further discusses how the Set works p/ remove duplicates. And only another detail, in the second Cód. , the Elms. will be converted p/ string p/ to suit the type (string) awaited by the object keys (see here). Because of this, objects also cease to be compared by ref. but rather by the result of their toString. Maybe, in that case, you’d better use a Map.

  • @Luizfelipe I think you’re right, I’ll do some tests.

Show 3 more comments

22

Here are 4 variants:

const array = ['a', 'b', 'b', 'c', 'c'];

using Javascript from the future

const unique = [...new Set(array)];

Like the @stderr referred in his answer are already planned (not yet officially launched) two concepts that can be used for the purpose of the question. One of them the Set, which is a new way of organizing eternal. The other is the spread syntax which allows to represent/convert eternal, more or less as an indication to write the object "in full". In this case combining the two, gives what is asked in the question.

This solution also resolves the problem that Gabriel mentioned and which exists in the solution with .filter(). (example: http://www.es6fiddle.net/iskjh2q8/)

Using .filter:

const unique = array.filter((el, i, arr) => arr.indexOf(el) == i);
console.log(unique); // ["a", "b", "c"]

The method .filter is natively available for arrays and accepts a function (callback). This function takes 3 arguments: the element to be iterated, the index (position) being iterated, and the original array. Using arr.indexOf(el) == i we guarantee that only the first time that each duplicate appears solves how true, thus cleaning the other elements.

Using .reduce and a ternary verifier.

const unique = array.reduce(
    (arr, el) => arr.concat(arr.includes(el) ? [] : [el]), []
);
console.log(unique); // ["a", "b", "c"]

In this case with the .reduce we can join elements to an initialized array in the second argument of the method reduce. It iterates all array positions and with ternary we check whether the element already exists in the new array being created within reduce.

Using an object to avoid duplicating keys

(only useful when we use Primitive)

const unique = ((obj, arr) => {
    arr.forEach(el => obj[el] = true);
    return Object.keys(obj);
})({}, array);
console.log(unique); // ["a", "b", "c"]

In this case we populate an object with keys formed by the elements of the initial array. Since objects only allow unique keys, when the iteration is complete we can return Object.keys(obj) which gives a new array with these unique keys.

17

SE6+

From ES6 you can also use the Set

The Set Object Lets you store Unique values of any type, whether Primitive values or Object References.

Take an example:

var valores = ['a', 'b', 'b', 'c', 'c', 1, 2, 2, 3];

var unique = new Set(valores);

alert([...unique]);

  • 3

    Set and spread... +1

  • 2

    Good indication of Set (+1)

  • 2

    You got that python :P

  • Ulia also uses sets, any language that leads to the powder of the letter the set definition will have.

8

Using array.filter

function array_unique(array){
    return array.filter(function(el, index, arr) {
        return index == arr.indexOf(el);
    });
}

var array = ['a', 'b', 'b', 'c', 'c'];

console.log('Array original:');
console.log( array);
console.log('Array após utilização de array_unique:');
console.log( array_unique(array));

  • I think it’s worth pointing out that as much filter how much indexOf are linear, this code is executed in quadratic time, which nay is efficient for cases where the number of elements is already becoming expressive. The difference is quite striking.

5

Quite simply, go through the array and place the items in a time array, and check whether or not the item exists in the time array.

function array_unique(array){
	var unique = [];
	for(var i in array){
		if(unique.indexOf(array[i])==-1){
			unique.push(array[i]);
		}
	}
	
	return unique;
}

var array = ['a', 'b', 'b', 'c', 'c'];
console.log(array_unique(array));

4

Another solution would be.

Array.prototype.getUnique = function(){
   var u = {}, a = [];
   for(var i = 0, l = this.length; i < l; ++i){
      if(u.hasOwnProperty(this[i])) {
         continue;
      }
      a.push(this[i]);
      u[this[i]] = 1;
   }
   return a;
}

var array = ['a', 'b', 'b', 'c', 'c'];
array.getUnique();

Source: SOEN

Browser other questions tagged

You are not signed in. Login or sign up in order to post.