聚合两个对象数组

时间:2019-01-16 15:50:45

标签: javascript arrays aggregate

假设我有以下两个数组:

const initial: Array<GivenObj> = [
  {name: 'a', times: 40, other: 50},
  {name: 'b', times: 10, other: 15},
  {name: 'c', times: 15, other: 12}
];

const toBeMerged: Array<GivenObj> = [
  {name: 'a', times: 45, other: 30},
  {name: 'c', times: 10, other: 10},
  {name: 'd', times: 23, other: 10}
];

这两个数组包含不同的值,但是键相似。我需要将此数据聚合到一个包含两个值但唯一的数组中。

在代码中,上面的两个数组应按以下方式聚合:

const aggregated: Array<GivenObj> = [
  {name: 'a', times: 85, other: 80},
  {name: 'b', times: 10, other: 15},
  {name: 'c', times: 25, other: 22},
  {name: 'd', times: 23, other: 10}
];

我想知道在两个数组之间聚合数据的最佳方法是什么。

7 个答案:

答案 0 :(得分:2)

我可以通过合并两个数组来实现此目的,然后对合并后的数组运行reduce方法。

在reduce中,它首先检查是否存在具有该名称的条目,如果不存在,则将该条目推送到结果数组。如果确实找到了现有条目,则它将创建不存在的任何属性,并添加已经存在的任何数字属性的值。无论您实际使用哪种情况,这都应该足够灵活。

const initial = [
  {name: 'a', times: 40, other: 50},
  {name: 'b', times: 10, other: 15},
  {name: 'c', times: 15, other: 12}
];

const toBeMerged = [
  {name: 'a', times: 45, other: 30},
  {name: 'c', times: 10, other: 10},
  {name: 'd', times: 23, other: 10}
];

const result = [ ...initial, ...toBeMerged ].reduce((arr, t) => {
  let existing = arr.filter(x => x.name == t.name)[0]
  if(!existing) arr.push(t)
  else {
    const keys = Object.keys(t)
    keys.forEach(key => {
      if(!existing.hasOwnProperty(key)) existing[key] = t[key]
      else if(typeof existing[key] === "number") existing[key] += t[key]
    })
  }
  
  return arr
}, [])

console.log(result)

答案 1 :(得分:1)

您可以减少给定的数据并寻找相同的name,然后进行更新,否则添加一个新对象。

需要

  • 一个新数组,其中包含initialtoBeMerged中的项目,
  • 通过以下方式减少项目

    • 在累加器name中寻找具有相同r的物品,
    • 检查是否找到了该项目,然后返回一个新的数组,其中包含已收集的itms和实际对象的副本
    • 否则将所需的属性增加一些值。

const
    initial = [{ name: 'a', times: 40, other: 50 }, { name: 'b', times: 10, other: 15 }, { name: 'c', times: 15, other: 12 }],
    toBeMerged = [{ name: 'a', times: 45, other: 30 }, { name: 'c', times: 10, other: 10 }, { name: 'd', times: 23, other: 10 }],
    merged = [...initial, ...toBeMerged].reduce((r, o) => {
        var temp = r.find(p => o.name === p.name);
        if (!temp) return [...r, { ...o }];
        temp.times += o.times;
        temp.other += o.other;
        return r;
    }, []);

console.log(merged);

答案 2 :(得分:0)

这是我过去处理此问题的方式。

  1. 创建一个final数组,其中将包含最终结果。
  2. 使用Array concat方法合并数组
  3. 串联的数组按name属性进行排序,这意味着所有a将按顺序排列,然后是b依此类推。
  4. forEach方法用于遍历连接的排序数组。如果当前元素具有与name数组的最后一个元素相同的final属性,则将el的数字属性添加到final数组的最后一个元素。否则,将el添加到最终数组的末尾。

const initial = [
  {name: 'a', times: 40, other: 50},
  {name: 'b', times: 10, other: 15},
  {name: 'c', times: 15, other: 12}
];

const toBeMerged = [
  {name: 'a', times: 45, other: 30},
  {name: 'c', times: 10, other: 10},
  {name: 'd', times: 23, other: 10}
];

let final = [];

initial.concat(toBeMerged).sort((a, b) => a.name > b.name).forEach(el => {
  if (final.length > 0 && el.name === final[final.length - 1].name) {
    final[final.length - 1].times += el.times;
    final[final.length - 1].other += el.other;
  } else {
    final.push(el);
  }
})

console.log(final);

答案 3 :(得分:0)

您可以在reduce的帮助下完成它。

  1. 首先使用concat合并两个数组。
  2. 现在在使用reduce的精简数组上,我们检查对象属性是否已经存在于output中,而不是在现有属性中添加timesother添加一个新属性。

const initial= [{name: 'a', times: 40, other: 50},{name: 'b', times: 10, other: 15},{name: 'c', times: 15, other: 12}];
const toBeMerged= [{name: 'a', times: 45, other: 30},{name: 'c', times: 10, other: 10},{name: 'd', times: 23, other: 10}];
let temp = initial.concat(toBeMerged)

let op = temp.reduce((output,current)=>{
  if( output[current.name] ){
    output[current.name].times += current.times
    output[current.name].other += current.other
  } else{
    output[current.name] = current;
  }
  return output;
},{})

console.log(Object.values(op))

答案 4 :(得分:0)

尝试此代码

const initial = [
  {name: 'a', times: 40, other: 50},
  {name: 'b', times: 10, other: 15},
  {name: 'c', times: 15, other: 12}
];

const toBeMerged = [
  {name: 'a', times: 45, other: 30},
  {name: 'c', times: 10, other: 10},
  {name: 'd', times: 23, other: 10}
];

//console.log(initial);

function arrayUnique(array) {
    var a = array.concat();
    for(var i=0; i<a.length; ++i) {
        for(var j=i+1; j<a.length; ++j) {
            if(a[i].name === a[j].name)
            {
                a[i].times +=a[j].times;
                a[i].other +=a[j].other;
                a.splice(j--, 1);
            }
        }
    }

    return a;
}


    // Merges both arrays and gets unique items
var array = arrayUnique(initial.concat(toBeMerged));
console.log(array);

答案 5 :(得分:0)

在这里,您有一种在要合并的新数组上使用reduce()findIndex()的方法。如果要合并的新对象已经存在(例如,某个对象的name属性匹配),我们将增加其余匹配属性并添加不存在的属性,否则将推送整个新对象:

const initial = [
  {name: 'a', times: 40, other: 50},
  {name: 'b', times: 10, other: 15},
  {name: 'c', times: 15, other: 12}
];

const toBeMerged = [
  {name: 'a', times: 45, other: 30, another: 76},
  {name: 'c', times: 10, other: 10},
  {name: 'd', times: 23, other: 10}
];

let newArray = toBeMerged.reduce((res, curr) =>
{
    let found = res.findIndex(x => x.name === curr.name);

    if (found >= 0)
    {
        res[found] = Object.keys(curr).reduce((r, c) =>
        {
           r[[c]] = (r[[c]] && c !== 'name') ? r[[c]] + curr[[c]] : curr[[c]];
           return r;
        }, res[found]);
    }
    else
    {
        res.push(curr);
    }

    return res;

}, initial);

console.log(newArray);

答案 6 :(得分:0)

使用传播运算符,解构,Array#reduce,Object#values和Map

const initial=[{name:'a',times:40,other:50},{name:'b',times:10,other:15},{name:'c',times:15,other:12}];const toBeMerged=[{name:'a',times:45,other:30},{name:'c',times:10,other:10},{name:'d',times:23,other:10}]

const res = [...[...initial, ...toBeMerged]
.reduce((a,{name,times,other})=>{
    const b = a.get(name);
    return a.set(name,{name, times: (b?b.times:0) + times, other: (b?b.other:0) + other});
}, new Map()).values()];

console.log(res);