如何将对象列表减少为重复

时间:2017-09-14 12:56:02

标签: javascript lodash

[为清晰起见而编辑]

使用lodash,给定一个对象数组:

var v = [{'a':1, 'b':1}, {'a':1, 'b':2}, {'a':1, 'c':1}];

如何返回这些对象(键和值)的交集对象?在这种情况下:

{'a':1}

我正在寻找每个对象中的键值对。

这似乎是_.reduce的任务,但我不确定如何找到重复的对象。

4 个答案:

答案 0 :(得分:1)

实际上,你可以使用散列对象使用Array#reduce,使用Object#keys来获取所有对象中出现的所有key:value对。

var v = [{'a':1, 'b':1}, {'a':1, 'b':2}, {'a': 1, 'c':1, 'b': 1}];

var hashCount = {};

var result = v.reduce(function(r, o) {
  Object.keys(o).forEach(function(key) { // iterate the object keys

    var hash = key + '_' + o[key]; // create the hash from the key:value pair

    hashCount[hash] = (hashCount[hash] || 0) + 1; // increment the hash in the hashCount

    // add the pair to the result when the hash count number is equal to the length of the array,
    if(hashCount[hash] === v.length) {
      r[key] = o[key];
    }
  });
  
  return r;
}, {});

console.log(result);

btw - 我的原始答案是为了应对出现在至少两个对象中的属性的情况。因此,如果您只想查找出现在2个对象(或任意数字)中的属性,请将此行if(hashCount[hash] === v.length) {更改为if(hashCount[hash] === 2) {

答案 1 :(得分:1)

您可以通过迭代键并检查值来减少对象。然后构建一个新对象并返回。

ls >> /path/to/file

ES6与Object.assign

var array = [{ a: 1, b: 1 }, { a: 1, b: 2 }, { a: 1, c: 1 }],
    result = array.reduce(function (a, b) {
        return Object.keys(a).reduce(function (o, k) {
            if (a[k] === b[k]) {
                o[k] = a[k];
            }
            return o;
        }, {});
    });

console.log(result);

答案 2 :(得分:1)

这是使用loDash

执行此操作的一种方法

var v = [{'a':1, 'b':1}, {'a':1, 'b':2}, {'c':1}];

let k = _.chain(v).map(Object.entries)
                  .flatten(true)
                  .filter((f,u,n) => {
                      let i = _.findLastIndex(n, z => (_.isEqual(f,z)));
                      return n.some((g,o) => (_.isEqual(f,g) && u!==o && u===i));
                  })
                  .map(x => ({[x[0]]:x[1]}))
                  .value()
         
console.log( k )
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>

它将对象重新分割,然后展平,然后根据对象相等进行过滤,使用_.isEqual,而不是字符串比较,然后映射回对象并从链中获取值

答案 3 :(得分:1)

使用_.reduce的解决方案:

var r = _.reduce(v.slice(1), function (result, item) {
    Object.keys(result).forEach(function (key) {
      if (!item.hasOwnProperty(key)) delete result[key];
    })
    return result;
  }, Object.assign({}, v[0]));

这个想法是使用一个项目作为结果,作为第三个参数(累加器)移交给reduce()。这是通过复制Object来完成的,因为它在算法中被修改,如下所示:Object.assign({}, v[0])

在reduce函数(第二个参数)中,我们检查结果的每个Property的实际项目。如果该项目没有,我们将其从结果中删除。

由于列表的第一项已经提供给函数,因此可以从数组中排除它以减少v.slice(1)所做的事情。

为什么这样做:

  1. 列表中的每个项目都可以用作初始交集,因为我们正在寻找所有对象中存在的所有属性,我们可以肯定地说我们不会忘记包含来自任何其他对象的任何其他属性

  2. 如果某个项目没有任何属于交叉点的属性,则该属性不是交叉点的一部分,需要从该位置删除。

  3. 注意:

    使用reduce的一个缺点是:它迭代列表中的每个项目,无论交集是否已经为空,算法可以停止。因此,对于大型对象列表,编写类似下面的常规函数​​可能会更快,这可能没有交集:

    function intersect (list) {
      var 
        remain = [].concat(list),
        result = Object.assign({}, remain.pop()),
        keys = Object.keys(result),
        item;
    
      while ((item = remain.pop()) != undefined && keys.length > 0) {
        keys.forEach(function (key) {
          if (!item.hasOwnProperty(key)) delete result[key];
        });
    
        keys = Object.keys(result);
      }
    
      return result;
    }