从对象数组中获取唯一元素数组

时间:2016-03-04 08:42:17

标签: javascript arrays underscore.js unique union

我有类似以下的数组:

files = [
       {name: 'Lorem', other: true},
       {name: 'Foo', other: true},
       {name: 'Bar', other: true}
      ];


files = [
       {name: 'Lorem', other: true},
       {name: 'Xxxxx', other: true}
      ];


files = [
       {name: 'Lorem', other: true},
       {name: 'Foo', other: true},
       {name: 'Epic', other: true},
       {name: 'Xxxxx', other: true}
      ];

我正在尝试使用Underscore获取具有唯一元素的合并数组,但它不起作用。这是我的代码:

function getAllFiles(alldocs) {
  var all = [];

  _.each(alldocs, function(element) {
    all = _.union(all, element.files);
  });

  return all;
}

但我得到一个包含重复项目的数组。

5 个答案:

答案 0 :(得分:2)

使用下划线你可以这样做:

files1 = [
       {name: 'Lorem', other: true},
       {name: 'Foo', other: true},
       {name: 'Bar', other: true}
      ];


files2 = [
       {name: 'Lorem', other: true},
       {name: 'Xxxxx', other: true}
      ];


files3 = [
       {name: 'Lorem', other: true},
       {name: 'Foo', other: true},
       {name: 'Epic', other: true},
       {name: 'Xxxxx', other: true}
      ];
//append all  json
all = _.union(files1,files2, files3);
//get unique by define function which returns name (deciding factor for unique)
all = _.uniq(all, function(d){return d.name});
console.log(all);//prints the unique elements

工作代码here

答案 1 :(得分:1)

普通Javascrift中的一个临时对象和Array#forEach()

的解决方案

var files1 = [{ name: 'Lorem', other: true }, { name: 'Foo', other: true }, { name: 'Bar', other: true }],
    files2 = [{ name: 'Lorem', other: true }, { name: 'Xxxxx', other: true }],
    result = function (array) {
        var o = {}, r = [];
        array.forEach(function (a) {
            if (!(a.name in o)) {
                o[a.name] = a;
                r.push(o[a.name]);
            }
        });
        return r;
    }(files1.concat(files2));

document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');

答案 2 :(得分:1)

您需要在union致电后应用uniq方法。

问题是uniq默认情况下使用===运算符来测试数组元素的相等性。因此,如果您有对象数组,则每个对象将通过引用进行比较,而不是值,这显然是不受欢迎的行为。这个问题可以通过为uniq提供额外的参数 - 回调函数(iteratee)来解决,该函数将数组元素转换为简单的可比较值。在您的情况下,您可以使用JSON.stringify方法返回对象的字符串表示。

function getAllFiles(alldocs) {
    var union = _.union.apply(null, alldocs.map(function(v) {
        return v.files;
    }));
    return _.uniq(union, function(v) {
        return JSON.stringify(v);
    });
}
var alldocs = [
    {files: [
       {name: 'Lorem', other: true},
       {name: 'Foo', other: true},
       {name: 'Bar', other: true}
    ]},
    {files: [
       {name: 'Lorem', other: true},
       {name: 'Xxxxx', other: true}
    ]},
    {files: [
       {name: 'Lorem', other: true},
       {name: 'Foo', other: true},
       {name: 'Epic', other: true},
       {name: 'Xxxxx', other: true}
    ]}
];
var result = getAllFiles(alldocs);

Fiddle

答案 3 :(得分:0)

使用lodash,您可以使用_.uniqBy

result = _.uniqBy(result, function (e) {
  return e.name;
});

https://jsfiddle.net/mw230kea/1/

答案 4 :(得分:0)

这是因为您正在使用对象数组而下划线不知道在比较项目时使用哪个对象属性(例如名称,其他), 这是一个干净的解决方案:

   files =  _.chain(files).indexBy("name").values();