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}]