Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get unique array of objects in javascripts [duplicate]

I want to get array having unique objects.

Say I have array of objects

[{"a":"b"},{"c":"d"},{"a":"b"}] 

and I want unique value of array i.e

[{"a":"b"},{"c":"d"}]

is there any simplest way to do this.

like image 896
Harshal_m_joshi Avatar asked Jun 03 '13 09:06

Harshal_m_joshi


2 Answers

If the array containing the same objects over and over again you can do make a function like this:

var oa = {"a":"b"},
    ob = {"c":"d"};

var array = [oa, ob, oa];

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

But this will most likely not work because the object even when they seams the same is different:

alert( {a: 1} === {a: 1} ); // false

But:

var a = {a: 1};
alert( a === a ); // true

And even this will be true:

var a = {a: 1},
    b = a;

alert( a === b ); // true

So you will have to test for that as well (this is a shallow caparation. One level objects):

function isEqual(a, b) {
    var prop;
    for( prop in a ) {
        if ( a[prop] !== b[prop] ) return false;
    }
    for( prop in b ) {
        if ( b[prop] !== a[prop] ) return false;
    }
    return true;
}

And we have to rewrite our unique function as well:

function unique(a) {
    var isAdded,
        arr = [];
    for(var i = 0; i < a.length; i++) {
        isAdded = arr.some(function(v) {
            return isEqual(v, a[i]);
        });
        if( !isAdded ) {
            arr.push(a[i]);
        }
    }
    return arr; 
}

Full Code:

var a = [{"a":"b"},{"c":"d"},{"a":"b"}],
    b = unique(a); // [{"a":"b"},{"c":"d"}]

function unique(a) {
    var isAdded,
        arr = [];
    for(var i = 0; i < a.length; i++) {
        isAdded = arr.some(function(v) {
            return isEqual(v, a[i]);
        });
        if( !isAdded ) {
            arr.push(a[i]);
        }
    }
    return arr; 
}
function isEqual(a, b) {
    var prop;
    for( prop in a ) {
        if ( a[prop] !== b[prop] ) return false;
    }
    for( prop in b ) {
        if ( b[prop] !== a[prop] ) return false;
    }
    return true;
}

Note the use of some methods is depending on ECMAScript 5th Edition:

Array.some
Array.indexOf

like image 79
Andreas Louv Avatar answered Oct 18 '22 18:10

Andreas Louv


The simplest option is to compare objects by their JSON representation:

uniq = function(xs) {
    var seen = {};
    return xs.filter(function(x) {
        var key = JSON.stringify(x);
        return !(key in seen) && (seen[key] = x);
    });
}

For example:

console.log(
    uniq([{"a":"b"},{"c":"d"},{"a":"b"},{"a":"b"}])
)

// [{"a":"b"},{"c":"d"}]

Also, I recommend underscore.js for this kind of stuff, see Check if duplicate array pairs exist using underscore only for more discussion and examples.

Some commenters raised a concern that JSON.stringify is inadequate when comparing objects that differ only by the order of keys. I guess that comes down to the definition of "equality": {a:1,b:2} and {b:2,a:1} might be considered equal in one context and different in another. Still, if you want such objects to be "equal", you can extend JSON.stringify to be something like this:

toSortedJSON = function(obj) {
    return JSON.stringify(
        typeof obj == "object" ?
            Object.keys(obj).sort().reduce(function(o, key) {
                return o[key] = toSortedJSON(obj[key]), o;
            }, {}) : obj
    );
}

Then modify uniq to accept the key function:

uniq = function(xs, key) {
    var seen = {};
    return xs.filter(function(x) {
        var k = (key || JSON.stringify)(x);
        return !(k in seen) && (seen[k] = 1);
    });
}

and, finally pass the custom serializer to uniq:

console.log(
    uniq([
        {"a":1, "b":2},
        {"x":33},
        {"b":2, "a":1},
    ], toSortedJSON)
)

// [{"a":1,"b":2},{"x":33}]
like image 32
georg Avatar answered Oct 18 '22 19:10

georg