如何在javascripts中获取唯一的对象数组

Har*_*shi 7 javascript arrays jquery

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

说我有对象数组

[{"a":"b"},{"c":"d"},{"a":"b"}] 
Run Code Online (Sandbox Code Playgroud)

我想要数组的唯一值ie

[{"a":"b"},{"c":"d"}]
Run Code Online (Sandbox Code Playgroud)

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

and*_*lrc 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; 
}
Run Code Online (Sandbox Code Playgroud)

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

alert( {a: 1} === {a: 1} ); // false
Run Code Online (Sandbox Code Playgroud)

但:

var a = {a: 1};
alert( a === a ); // true
Run Code Online (Sandbox Code Playgroud)

即使这样也是如此:

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

alert( a === b ); // true
Run Code Online (Sandbox Code Playgroud)

所以你也必须测试它(这是一个浅层的caparation.一个级别的对象):

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;
}
Run Code Online (Sandbox Code Playgroud)

我们还必须重写我们独特的功能:

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; 
}
Run Code Online (Sandbox Code Playgroud)

完整代码:

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;
}
Run Code Online (Sandbox Code Playgroud)

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

Array.some
Array.indexOf


geo*_*org 5

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

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

例如:

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

// [{"a":"b"},{"c":"d"}]
Run Code Online (Sandbox Code Playgroud)

此外,我推荐 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
    );
}
Run Code Online (Sandbox Code Playgroud)

然后修改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);
    });
}
Run Code Online (Sandbox Code Playgroud)

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

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

// [{"a":1,"b":2},{"x":33}]
Run Code Online (Sandbox Code Playgroud)