合并具有相同属性的数组对象

时间:2018-02-02 15:24:39

标签: javascript underscore.js lodash

我正在做我的一个前端项目,我有一种情况,我必须根据某些条件合并/添加阵列中存在的对象。条件是

  • 只应合并那些具有相同标签的对象。
  • 对于具有相同标签的对象,如果对象' a'具有b对象中存在的属性,必须添加该值,否则只需复制属性。

所以我的输入是

[
  {
    label: 'label-1',
    published: 1,
    draft: 2,
    id: 'some1'
  },
  {
    label: 'label-1',
    published: 2,
    status: 0,
    draft: 1,
    id: 'some4'
  },
  {
    label: 'label-2',
    published: 1,
    draft: 14,
    id: 'some2'
  },
  {
    label: 'label-2',
    published: 12,
    status: 0,
    draft: 14,
    id: 'some3'
  }
]

和期待

    [
      {
        label: 'label-1',
        published: 3,
        draft: 4,
        status: 0
      },
{
        label: 'label-2',
        published: 13,
        draft: 28,
        status: 0
      }
    ]

目前我使用以下代码实现相同目的,但发现它并不整洁。有什么方法可以轻松实现这一点。



function mapData(data) {
    let groupData = _.groupBy(data, 'label');
    let stackBarData = [];
    Object.keys(groupData).forEach((key) => {
      if (groupData[key] && groupData[key].length > 0) {
        let temp = Array.from(groupData[key]).reduce((a, b) => {
          for (let property in b) {
            if (b.hasOwnProperty(property)) {
              if (property !== 'label' && property !== 'id' && property !== 'Others') {
                a[property] = (a[property] || 0) + b[property];
              } else {
                a[property] = b[property];
              }
            }
          }
          return a;
        }, {});
        stackBarData.push(temp);
      }
    });
    return stackBarData;
  }




请帮忙。

2 个答案:

答案 0 :(得分:2)

这是一个纯ES6函数,它根据唯一标签收集数字对象值,将它们添加起来(这就是你的行为):

function mapData(data) {
    const grouped = new Map(data.map( ({label}) => [label, { label }] ));
    for (let obj of data) {
        let target = grouped.get(obj.label);
        for (let [key, val] of Object.entries(obj)) {
            if (typeof val === 'number') {
                target[key] = (target[key] || 0) + val;
            }
        }
    }
    return [...grouped.values()];
}

// Sample data
const data = [{label: 'label-1',published: 1,draft: 2,id: 'some1'},{label: 'label-1',published: 2,status: 0,draft: 1,id: 'some4'},{label: 'label-2',published: 1,draft: 14,id: 'some2'},{label: 'label-2',published: 12,status: 0,draft: 14,id: 'some3'}];

console.log(mapData(data));
.as-console-wrapper { max-height: 100% !important; top: 0; }

如果您想要排除数字属性,那么拥有一组您感兴趣的显式属性可能会更好:

const props = new Set(['status', 'published', 'draft']);
// ... etc
//
if (props.has(key)) { 
    target[key] = (target[key] || 0) + val;
}
// ...

答案 1 :(得分:1)

<强> Lodash

_.groupBy()标签_.map()组,并使用_.mergeWith()合并每个组,_.omit() id < / em>的。合并组时,如果当前值是数字,则将当前值和新值相加,如果不返回use FOS\RestBundle\Controller\Annotations as JMS; - 如果定制器返回未定义,则由方法处理合并。

&#13;
&#13;
undefined
&#13;
const arr = [{"label":"label-1","published":1,"draft":2,"id":"some1"},{"label":"label-1","published":2,"status":0,"draft":1,"id":"some4"},{"label":"label-2","published":1,"draft":14,"id":"some2"},{"label":"label-2","published":12,"status":0,"draft":14,"id":"some3"}]

const result = _(arr)
  .groupBy('label')
  .map((g) => _.omit(_.mergeWith({}, ...g, (objValue, srcValue) => _.isNumber(objValue) ? objValue + srcValue : undefined), 'id'))
  .value()
  
console.log(result)
&#13;
&#13;
&#13;

<强> ES6

使用Array.reduce()迭代数组。在每次迭代时检查累加器(Maphas 标签,如果没有添加带有标签的空对象作为键。使用keys迭代当前对象Array.forEach(),忽略 id ,并对数值求和。要获得一个数组传播Map.values()

&#13;
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
&#13;
&#13;
&#13;