46

The description of jQuery.unique() states:

Sorts an array of DOM elements, in place, with the duplicates removed. Note that this only works on arrays of DOM elements, not strings or numbers.

With the description in mind, can someone explain why the code below works?

<div></div>
<div></div>​

var arr = ['foo', 'bar', 'bar'];

$.each(arr, function(i, value){
    $('div').eq(0).append(value + ' ');
});

$.each($.unique(arr), function(i, value){
    $('div').eq(1).append(value  + ' ');
});
​

http://jsfiddle.net/essX2/

Thanks

Edit: Possible solution:

function unique(arr) {
var i,
    len = arr.length,
    out = [],
    obj = { };

for (i = 0; i < len; i++) {
    obj[arr[i]] = 0;
}
for (i in obj) {
    out.push(i);
}
return out;
};
14
  • 3
    I guess it just "happens to work" here, but it should not be trusted to work in other situations than described in the docs. Commented Apr 17, 2012 at 13:15
  • var arr = ['bar', 'bar', 'foo', 'foo', 'bar', 'bar', 'foo', 'bar']; this array will contain duplicates Commented Apr 17, 2012 at 13:19
  • @Johan use an object and it will: jsfiddle.net/essX2/2 Commented Apr 17, 2012 at 13:19
  • 1
    @Johan yet it shows that it isn't designed for other uses and might fail. If you are looking for something more robust have you considered using underscore.js? Commented Apr 17, 2012 at 13:21
  • 1
    An array is not a string - or is it? See the section on unique in Paul Irish's article here: paulirish.com/2010/duck-punching-with-jquery There is a modification to unique. Commented Apr 17, 2012 at 13:22

9 Answers 9

105

Although it works, you should probably take into consideration the function description. If the creators say that it is not designed for filtering arrays of anything else than dom elements, you should probably listen to them.
Besides, this functionality is quite easy to be reproduced :

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

(demo page)

Update:

In order for this code to work in all browsers (including ie7 that doesn't support some array features - such as indexOf or filter), here's a rewrite using jquery functionalities :

  • use $.grep instead of Array.filter
  • use $.inArray instead of Array.indexOf

Now here's how the translated code should look like:

function unique(array) {
    return $.grep(array, function(el, index) {
        return index === $.inArray(el, array);
    });
}

(demo page)

Sign up to request clarification or add additional context in comments.

5 Comments

Thanks for the code snippet. indexOf doesnt work on arrays in ie7 if im not misstaken. I need it to work there as well. Ive updated my question with another possible solution
You can use jquery's inArrayS instead of indexOf. See the update please.
@Jonah You were right.. I updated my answer again, because I fell in the same trap. ie7 and lower doesn't support Array.filter too :)). See the update.
This uses loose equality ==. lodash uses strict equality === and PHP uses a hybrid form by casting to strings first. Might I recommend including an optional strict argument?
well, you could use the strict equality operator (===), but in these cases, both of the operands are always numeric, so it's won't make any significant difference, but anyway, thanks for the feedback. I will update the answer to use strict equality, because.. that's the way I should've written the code 2 years ago anyway:)
23

It might work on an array strings, etc, but it has not been designed for that use...

Notice that the code for unique() is hiding in Sizzle as uniqueSort: github source

While some of that extra code might seem like it would work on any array, pay close attention to sortOrder as defined here. It does a lot of extra work to put things in "document order" - hence why the documentation states that it should only be used on arrays of DOM elements.

1 Comment

NOTE: "As of jQuery 3.0, jQuery.unique() is deprecated and just an alias of jQuery.uniqueSort(). Please use that method instead."
15

I know unique works with DOM but this WORKS on arrays of int:

$.unique(arr.sort());

Comments

9

If not limited using jQuery, consider to use Set from ES6.

var arr = ['foo', 'bar', 'bar'];
Array.from(new Set(arr)); // #=> ["foo", "bar"]

Working for Firefox 45, Safari 9 and Chrome 49.

Comments

4

$.unique will remove duplicate DOM elements, not identical DOM elements. When you try to use it on strings, you get unpredictable behavior and the sorting will (probably) fail.

It's a function intended for internal use by jQuery only, and won't be useful to mere mortals like you and I.

1 Comment

I'm saying that $.unique is explicitly documented as accepting an array of DOM elements. Any attempts to use it on an array of strings is technically wrong, and will lead to undocumented and unpredictable behavior.
3

There's a quick way to extend the jQuery.unique() function to work on arrays containing elements of any type.

(function($){

    var _old = $.unique;

    $.unique = function(arr){

        // do the default behavior only if we got an array of elements
        if (!!arr[0].nodeType){
            return _old.apply(this,arguments);
        } else {
            // reduce the array to contain no dupes via grep/inArray
            return $.grep(arr,function(v,k){
                return $.inArray(v,arr) === k;
            });
        }
    };
})(jQuery);

// in use..
var arr = ['first',7,true,2,7,true,'last','last'];
$.unique(arr); // ["first", 7, true, 2, "last"]

var arr = [1,2,3,4,5,4,3,2,1];
$.unique(arr); // [1, 2, 3, 4, 5]

http://www.paulirish.com/2010/duck-punching-with-jquery/ - example #2

Comments

0

$.unique will only remove duplicate DOM element, if you need it for array :

var result=[] ;
$.each([12,1,2,4,3,1,4,3,3,2,111], 
        function(i,e){ if($.inArray(e,result)===-1) result.push(e) ;});
result;

Comments

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

    function unique(array)
    {
    var unique_arr=[];
    array.forEach(function(i,e)
    {
    if(unique_arr.indexOf(i)===-1) unique_arr.push(i);
    });
    return unique_arr;
    }
    console.log(unique(array));

Comments

0

OK, so without Sizzle a shorthand for jQuery will be appreciate!

Based on the gion_13 answer, I ve just rewrite to make a native Array implementation.

Array.prototype.unique = function() { 
    let _array = this;
    return $.grep(_array, function(el, index) {
        return index === $.inArray(el, _array);
    });
};

Edited to be consistent ES shorter...

Array.prototype.unique=function(){let _array=this;return $.grep(_array,function(el, index){return index===$.inArray(el,_array);});};

In this case test done:

var A = ['1', 'green', true, 'blue', 1, (!false), 'toto', 'green', (!!0) ];

console.log( A );
// Array(9) [ "1", "green", true, "blue", 1, true, "toto", "green", false ]

console.log( A.unique() );
//Array(7) [ "1", "green", true, "blue", 1, "toto", false ]

Note about evclid that $.unique(arr.sort()); works fine but we lose order (:

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.