【问题标题】:Get array of unique elements from arrays of objects从对象数组中获取唯一元素数组
【发布时间】:2016-03-04 08:42:17
【问题描述】:

我有如下数组:

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

我正在尝试使用带有下划线的独特元素获得一个合并数组,但它不起作用。这是我的代码:

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

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

  return all;
}

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

【问题讨论】:

  • 你也可以使用underscorejs.org/#uniqunion
  • 下面给出的解决方案都只检查“名称”属性,但您可能希望区分“名称”和“其他”属性。循环遍历数组并检查两者。如果它只是您要检查的单个值,您可以使用地图并减少单线。

标签: javascript arrays underscore.js unique union


【解决方案1】:

使用下划线可以这样做:

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

【讨论】:

    【解决方案2】:

    纯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>');

    【讨论】:

      【解决方案3】:

      你需要在union调用后应用uniq方法。

      问题在于uniq 默认使用=== 运算符来测试数组元素是否相等。因此,如果您有对象数组,则每个对象都将通过 reference 进行比较,而不是值,这显然是不希望的行为。这个问题可以通过为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

      【讨论】:

        【解决方案4】:

        使用lodash,可以使用_.uniqBy

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

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

        【讨论】:

          【解决方案5】:

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

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2022-01-10
            • 2020-11-13
            • 1970-01-01
            • 2011-07-19
            • 2018-11-23
            • 2018-06-24
            相关资源
            最近更新 更多