在Javascript中使用可能的空值压缩两个集合(可用lodash)

时间:2016-12-14 21:50:55

标签: javascript lodash

我有两个对象数组。每个集合对象包含类似的属性。我正在尝试根据特定属性将两个集合压缩在一起。但是,任何一个数组中的特定对象都可能不一定具有在另一个数组中具有匹配属性值的对象。在这些情况下,我想要空值。以下是我想做的一个例子:

var arr1 = [
  { id: '1', text: 'arr1 - one' },
  { id: '2', text: 'arr1 - two' },
  { id: '3', text: 'arr1 - three' }
];

var arr2 = [
  { id: '1', text: 'arr2 - one' },
  { id: '2', text: 'arr2 - two' },
  { id: '4', text: 'arr2 - four' }
];

结果:

{ 
  '1': [
    { id: '1', text: 'arr1 - one' },
    { id: '1', text: 'arr2 - one' }
  ]

  '2': [
    { id: '2', text: 'arr1 - two' },
    { id: '2', text: 'arr2 - two' }
  ],

  '3': [
    { id: '3', text: 'arr1 - three' },
    null
  ],

  '4': [
    null,
    { id: '4', text: 'arr2 - four' }
  ]

我在项目中已经有了lodash 4依赖项,因此欢迎使用该库的答案。

5 个答案:

答案 0 :(得分:1)

function zip(a, b, propName) {
    const result = new Map();
    a.forEach(i=> result.set(i[propName], [i, null]));
    b.forEach(i=> {
       let item = result.get(i[propName]);
       item ? (item[1] = i) : (result.set(i[propName], [null, i]));
    });
    return result;
}

var arr1 = [
  { id: '1', text: 'arr1 - one' },
  { id: '2', text: 'arr1 - two' },
  { id: '3', text: 'arr1 - three' }
];

var arr2 = [
  { id: '1', text: 'arr2 - one' },
  { id: '2', text: 'arr2 - two' },
  { id: '4', text: 'arr2 - four' }
];
console.log(JSON.stringify([...zip(arr1, arr2, 'id')], null, '  '));

答案 1 :(得分:1)

_.chain(arr1)
    .concat(arr2)
    .map('id')
    .uniq() //get all possible ids without dublicates
    .reduce(function (result, id) {
        result[id] = _.map([arr1, arr2], function (arr) { //find object in each array by id
            return _.find(arr, {id: id}) || null;        //if not found set null
        });
        return result;
    }, {})
    .value();

答案 2 :(得分:0)

根据列出的要求,下面应该有效(使用Ramda,我相信使用的函数应该符合lodash/fp中的一个

var arr1 = [
  { id: '3', text: 'arr1 - one' },
  { id: '2', text: 'arr1 - two' },
  { id: '1', text: 'arr1 - three' }
];

var arr2 = [
  { id: '4', text: 'arr2 - one' },
  { id: '2', text: 'arr2 - two' },
  { id: '1', text: 'arr2 - four' }
];

var idList = R.pipe(
  R.concat,
  R.map(R.prop('id')),
  R.uniq,
  R.sortBy(R.identity)
)(arr1, arr2);

var findById = (id) => R.find(R.propEq('id', id));

return R.map(
  (id) => [
    findById(id)(arr1),
    findById(id)(arr2)
  ]
)(idList);

这是link。它正在返回undefined而不是null,但如果重要的话,您可以映射它以更改它。

但是,根据使用的结果,如果根本不需要null值,则会有更简单的版本groupWith

return R.pipe(
  R.concat,
  R.sortBy(R.prop('id')),
  R.groupWith(R.eqProps('id'))
)(arr1, arr2);

link

答案 3 :(得分:0)

使这有点困难的是每个分组中需要空值,这与它们被分组的顺序相匹配。例如,如果您不需要空值,则此问题将简单如下:

_.groupBy(arr1.concat(arr2), 'id')

但是,要分组和维护空值,您需要添加一些groupBy未预先烘焙的冗余。您可以编写自己的组功能:

function group(...arrs) { // extensible to any number of arrays
  // construct an object with empty arrays for all available ids
  let rslt = _.chain(arrs)
              .flatten()
              .map(el => el.id)
              .uniq()
              .reduce((memo, el) => {
                memo[el] = []
                return memo
              }, {})
              .value()
  // as we iterate, first set resulting object's bucket value to null 
  // Replace this value if it exists while iterating
  _.each(arrs, (arr, i) => {
    _.each(rslt, v => {
      v.push(null)
    })
    _.each(arr, el => {
      rslt[el.id][i] = el
    })
  })
  return rslt
}

var arr1 = [{
  id: '3',
  text: 'arr1 - one'
}, {
  id: '2',
  text: 'arr1 - two'
}, {
  id: '1',
  text: 'arr1 - three'
}];

var arr2 = [{
  id: '4',
  text: 'arr2 - one'
}, {
  id: '2',
  text: 'arr2 - two'
}, {
  id: '1',
  text: 'arr2 - four'
}];

console.log(group(arr1, arr2))
<script src="https://cdn.jsdelivr.net/lodash/4.17.2/lodash.min.js"></script>

^运行代码段以查看结果日志。

答案 4 :(得分:0)

您可以使用_.groupBy()_.mapValues()

执行此操作

&#13;
&#13;
const zipByKey = (arr1, arr2, zipKey) => {
  // group arr2 by the zipKey
  const group2 = _.groupBy(arr2, zipKey);
  
  return _(arr1)
    // group arr1 by the zipKey
    .groupBy(zipKey)
    // merge group1 with group2, if object is not in group1 substitute with null
    .mergeWith(group2, (objValue, srcValue) => (objValue || [null]).concat(srcValue))
    // map the groups, if object is not in group2 substitute with null
    .mapValues((group, zipKey) => group2[zipKey] ? group : group.concat(null))
    .value();
}

const arr1 = [{"id":"1","text":"arr1 - one"},{"id":"2","text":"arr1 - two"},{"id":"3","text":"arr1 - three"}], arr2 = [{"id":"1","text":"arr2 - one"},{"id":"2","text":"arr2 - two"},{"id":"4","text":"arr2 - four"}];

const result = zipByKey(arr1, arr2, 'id');

console.log(result);
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.2/lodash.min.js"></script>
&#13;
&#13;
&#13;