【问题标题】:How to get unique array of objects in javascripts [duplicate]如何在javascripts中获取唯一的对象数组[重复]
【发布时间】:2013-05-29 09:55:09
【问题描述】:

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

假设我有一个对象数组

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

我想要数组的唯一值,即

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

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

【问题讨论】:

  • 是的,可能有。
  • 没有简单的方法 - 您需要手动完成。首先编写一个比较器函数,该函数接受 2 个对象并根据对象是否相等返回真/假。然后用这个比较器循环数组。
  • 这不是骗子,你有一个可以查找的固定属性,这里你没有。
  • @harsha 这不是同一个问题。在您链接的问题中,通过一个特定的键检查重复性。在这里,任何对象的属性集都不是固定的,所有对象都必须相等。
  • 对不起,我的错,发布了错误的链接。将删除它。

标签: javascript jquery arrays


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

    最简单的选择是通过 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 来处理此类内容,请参阅 Check if duplicate array pairs exist using underscore only 了解更多讨论和示例。

    一些评论者担心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接受按键功能:

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

    【讨论】:

    • 小心:JSON 表示不可靠。在 JS 对象中,属性的顺序未定义。 {'a': 'b', 'c': 'd'}{'c': 'd', 'a': 'b'} 实际上是同一个对象,但 JSON 表示可能不一样。
    • 您能确定{a: 1, b: 1}{b: 1, a: 1} 的字符串化方式相同吗?
    • @RoToRa:请参阅链接线程中的my answer
    • @thg435 也许你应该澄清一下?
    • @NULL:添加了一些东西。
    猜你喜欢
    • 2020-09-21
    • 2018-05-25
    • 2023-04-07
    • 2012-06-30
    • 2019-10-20
    • 2021-03-23
    • 2022-01-21
    • 2019-01-03
    • 1970-01-01
    相关资源
    最近更新 更多