7

我想获得具有唯一对象的数组。

说我有对象数组

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

我想要数组的唯一值,即

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

有没有最简单的方法来做到这一点。

4

2 回答 2

7

如果数组一遍又一遍地包含相同的对象,你可以做一个这样的函数:

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

但这很可能不起作用,因为即使它们接缝相同,对象也是不同的:

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

但:

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

甚至这将是真的:

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

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

因此,您还必须对此进行测试(这是一个浅薄的描述。一级对象):

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

我们还必须重写我们独特的函数:

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

完整代码:

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

请注意,某些方法的使用取决于 ECMAScript 第 5 版:

Array.some
Array.indexOf

于 2013-06-03T09:33:35.117 回答
5

最简单的选择是通过对象的 JSON 表示来比较对象:

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

例如:

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

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

此外,我推荐使用 underscore.js 来处理这类内容,请参阅使用下划线检查是否存在重复的数组对,以获取更多讨论和示例。

一些评论者提出了一个问题,JSON.stringify即在比较仅按键顺序不同的对象时是不充分的。我想这归结为“平等”的定义:{a:1,b:2}并且{b:2,a:1}在一种情况下可能被认为是平等的,而在另一种情况下则不同。不过,如果您希望这些对象“相等”,您可以扩展JSON.stringify为如下所示:

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
    );
}

然后修改uniq接受key函数:

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

并且,最后将自定义序列化程序传递给uniq

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

// [{"a":1,"b":2},{"x":33}]
于 2013-06-03T09:42:07.773 回答