简体   繁体   English

聚合两个对象数组

[英]Aggregate two arrays of objects

Let's say I've got these two arrays: 假设我有这两个数组:

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

These two arrays contain different values, but similar keys. 这两个数组包含不同的值,但类似的键。 I need to aggregate this data to a single array that will contain both of their values, but uniquely. 我需要将这些数据聚合到一个包含其两个值的唯一数组中。

In code, the two arrays above should be aggregated as follows: 在代码中,上面的两个数组应该聚合如下:

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

I was wondering what's the best way to aggregate data between two arrays. 我想知道在两个数组之间聚合数据的最佳方法是什么。

I'd approach this by merging the two arrays, then running a reduce against that combined array. 我通过合并两个数组,然后对该组合数组运行reduce来解决这个问题。

Inside the reduce, it first checks to see if an entry with that name exists, if not it pushes that entry to the result array. 在reduce中,它首先检查是否存在具有该名称的条目,如果不存在,则将该条目推送到结果数组。 If it does find an existing entry, it creates any property that doesn't exist, and adds the values of any numerical properties that already exist. 如果确实找到了现有条目,则会创建任何不存在的属性,并添加已存在的任何数字属性的值。 This should be flexible enough for whatever your actual use case is. 无论您的实际用例如何,这都应该足够灵活。

 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) 

You could reduce the given data and look for same name , then update, otherwise add a new object. 您可以减少给定数据并查找相同的name ,然后更新,否则添加新对象。

It takes 它需要

  • a new array with items from initial and toBeMerged , 包含initialtoBeMerged项的新数组,
  • reducing the items by 减少项目

    • looking for an item with same name in the accumulator r , 在累加器r寻找具有相同name的项目,
    • checking if the item is not found, then return a new array with collected itms and a copy of the actual object 检查是否找不到该项,然后返回一个新数组,其中包含收集的itms和实际对象的副本
    • otherwise increment the needed properties with some values. 否则用一些值增加所需的属性。

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

Here is how I have approached this problem in the past. 以下是我过去处理此问题的方法。

  1. Create a final array, which will contain the final result. 创建一个final数组,其中包含最终结果。
  2. The arrays are merged using the Array concat method 使用Array concat方法合并数组
  3. The concatenated array is sorted by the name property, meaning that all the a's will be in order, then the b's, etc. 连接数组按name属性排序,这意味着所有的a将按顺序排列,然后是b,等等。
  4. The forEach method is used to iterate through the concatenated, sorted array. forEach方法用于遍历连接的排序数组。 If the current element has the same name property as the last element of the final array, then add the numeric properties of el to the last element of the final array. 如果当前元素与final数组的最后一个元素具有相同的name属性,则将el的数字属性添加到final数组的最后一个元素。 Otherwise, add el to the end of the final array. 否则,将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); 

You can do it with help of reduce . 你可以在减少的帮助下做到这一点。

  1. First merge both the array's using concat . 首先使用concat合并数组。
  2. Now on the concated array using reduce we check if the object property is already present in output than we add times and other in existing property if not than we add a new property. 现在在使用reduce的concated数组上,我们检查对象属性是否已经存在于output不是我们在现有属性中添加other times ,如果不是我们添加新属性。

 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)) 

Try this code 试试这个代码

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

Here you have one approach using reduce() and findIndex() over the new array to be merged. 在这里,你有一种方法使用reduce()findIndex()来合并新的数组。 If a new object to be merged already exists (ie the name property match for some object), we increment the rest of the matching properties and add the non-existing ones, otherwise we push the entire new object: 如果已经存在要合并的新对象(即某个对象的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); 

Using spread operator, destructuring, Array#reduce, Object#values and Map 使用扩展运算符,解构,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); 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM