This question already has an answer here:
Javascript: Merge Array of Objects, summing values with same key
(1 answer)
Closed 10 months ago.
if I have two (large) arrays that specify a key and a numeric value
var a = [
{ gtin: 'a1', quantity: 1 },
{ gtin: 'a3', quantity: 1 },
];
var b = [
{ gtin: 'a1', quantity: 1 },
{ gtin: 'a4', quantity: 1 },
];
what is the easiest way to get a single array that sums the quantities?
(Lodash ok, fewest iterations over array preferred)
ie
[
{ gtin: 'a1', quantity: 2 },
{ gtin: 'a3', quantity: 1 },
{ gtin: 'a4', quantity: 1 },
];
You could use a Map to keep track of gtin and its accumulated quantity, and then transform it back to array
const a = [
{ gtin: 'a1', quantity: 1 },
{ gtin: 'a3', quantity: 1 },
];
const b = [
{ gtin: 'a1', quantity: 1 },
{ gtin: 'a4', quantity: 1 },
];
const res = Array.from(
a
.concat(b)
.reduce(
(map, el) => map.set(el.gtin, (map.get(el.gtin) || 0) + el.quantity),
new Map()
)
).map(([gtin, quantity]) => ({ gtin, quantity }));
console.log(res);
References
Map
Related
This question already has answers here:
Javascript: Merge Array of Objects, summing values with same key
(1 answer)
How to merge two arrays of objects, and sum the values of duplicate object keys in JavaScript?
(2 answers)
Closed 9 months ago.
let obj = [
{
name: "a",
quantity: 2
},
{
name: "b",
quantity: 4
},
{
name: "c",
quantity: 88
}
]
let obj2 = [
{
name: "a",
quantity: 2
}
]
I want to group two object array but if object which has a same name already exists then merge.
For example, there are objects which name is "a" and I want to merge them together.
Output what I want is like
[
{
name: "a",
quantity: 4
},
{
name: "b",
quantity: 4
},
{
name: "c",
quantity: 88
}
]
The quantity of object which name is "a" is add together.
Is there anyway to do this?
let obj = [
{
name: "a",
quantity: 2
},
{
name: "b",
quantity: 4
},
{
name: "c",
quantity: 88
}
]
let obj2 = [
{
name: "a",
quantity: 2
}
]
let obj3 = [...obj, ...obj2];
let obj4 = obj3.reduce( (curr, ele) => {
let exist = curr.filter( cur => cur.name == ele.name)
if (exist.length) exist[0].quantity += ele.quantity
else curr.push({...ele})
return curr
}, [])
let obj5 = Object.values(
obj3.reduce((res, {name, quantity}) => {
let ele = res[name] ??= {name}
ele['quantity'] = (ele['quantity'] ?? 0) + quantity
return res
}, {})
)
console.log(obj4, obj5)
You can use forEach() for this.
let obj = [
{
name: "a",
quantity: 2
},
{
name: "b",
quantity: 4
},
{
name: "c",
quantity: 88
}
]
let obj2 = [
{
name: "a",
quantity: 2
}
]
obj.forEach((element)=>{
obj2.forEach((e)=>{
if(element.name == e.name){
element.quantity = element.quantity+e.quantity
}
})
})
console.log(obj);
This question already has answers here:
Merge two array of objects based on a key
(23 answers)
Closed last year.
I have two Objects one of them has the Store Name and the other object has the Price for an item along with the Store ID on both objects. Such as;
obj1 = [
{id: 1,name: "Store1"},
{id: 2,name: "Store2"},
{id: 3,name: "Store3"}
];
obj2= [
{ id: 1, price: 100 },
{ id: 2, price: 200 },
{ id: 3, price: 300 }
];
What I want to achieve is that compare obj1 id with obj2 id if they are the same get the price and the store name from the same id. What is the best way to achieve this? I have been trying to use Array.map or filter but can't really make it work. Thank you!
You can use map & find
const obj1 = [{
id: 1,
name: "Store1"
},
{
id: 2,
name: "Store2"
},
{
id: 3,
name: "Store3"
},
{
id: 4,
name: "Store3"
}
];
const obj2 = [{
id: 1,
price: 100
},
{
id: 2,
price: 200
},
{
id: 3,
price: 300
}
];
const newData = obj1.map((item, index) => {
return {
...item,
// if the item exist in obj2 then get the price else assign empty string
price: obj2.find(elem => elem.id === item.id) ? .price || ''
}
});
console.log(newData)
This question already has answers here:
Merge two array of objects based on a key
(23 answers)
Closed 1 year ago.
I have two arrays as input (array1 & array2) for which I want to check if there is a match on id.
If there is a match they should be included in a new array called result.
array1 = [
{ x_id:6711230070958, id:279482 },
{ x_id:6770878283950, id:213 },
{ x_id:6753301168302, id:330120 }
];
array2 = [
{ id: 279482, stock: 9 },
{ id: 31231, stock: 2 },
{ id: 330120, stock: 2 }
];
result [
{ x_id:6711230070958, id: 279482, stock: 9 },
{ x_id:6753301168302, id: 330120, stock: 2 }
]
For finding the matches I tried using a filter with includes.
Anybody some thoughts on this?
Try this
array1 = [
{ x_id:6711230070958, id:279482 },
{ x_id:6770878283950, id:213 },
{ x_id:6753301168302, id:330120 }
];
array2 = [
{ id: 279482, stock: 9 },
{ id: 31231, stock: 2 },
{ id: 330120, stock: 2 }
];
let arr3 = array1.map((item, i) => Object.assign({}, item, array2[i]));
console.log(arr3)
Try this:
array1 = [
{ x_id:6711230070958, id:279482 },
{ x_id:6770878283950, id:213 },
{ x_id:6753301168302, id:330120 }
];
array2 = [
{ id: 279482, stock: 9 },
{ id: 31231, stock: 2 },
{ id: 330120, stock: 2 }
];
result = [];
array1.forEach(ele=> {
let match = array2.find(e => e.id == ele.id);
if(match)
result.push(Object.assign({}, ele, match))
})
I am trying to transform an array of objects to a 'grouped' and sorted output array in JavaScript, preferably the ES6-way (e.g. using .map, .reduce, etc.).
Summary:
array of objects
each object is an 'item': a1,a2,b1,b2,...
each object has a 'section' property which is like a group/category
the desired output array should return the item objects grouped by 'section'
the sorting order of the output arrays of sections and items is defined in a property as well
const data = [
{ section: 'A', item: 'a1', section_order: 2, item_order: 2 },
{ section: 'B', item: 'b1', section_order: 1, item_order: 2 },
{ section: 'A', item: 'a2', section_order: 2, item_order: 1 },
{ section: 'B', item: 'b2', section_order: 1, item_order: 1 }
];
const desiredOutput = [
{
section: 'B', // should come first as section_order = 1
items: [
{ section: 'B', item: 'b2', section_order: 1, item_order: 1 }, // should come first as item_order = 1
{ section: 'B', item: 'b1', section_order: 1, item_order: 2 }, // should come second as item_order = 2
]
},
{
section: 'A', // should come second as section_order = 2
items: [
{ section: 'A', item: 'a2', section_order: 2, item_order: 1 },
{ section: 'A', item: 'a1', section_order: 2, item_order: 2 },
]
}
];
I saw an example that gets me somewhere in the right direction - but not exactly to the desired output and without catering for the sorting-order:
const result = data.reduce((accum, currElm) => {
const currSection = currElm['section'];
accum[currSection] = (accum[currSection] || []).concat(currElm);
return accum;
}, {});
You should sort your data first. The sort function look like this
data.sort((a, b) => (a.section_order - b.section_order) || (a.item_order - b.item_order));
As you can see, we split the condition into 2 parts:
(a.section_order - b.section_order)
(a.item_order - b.item_order)
It means that you sort section_order then by item_order.
After that, you can loop just one time by using dictionary power like below
const data = [
{ section: 'A', item: 'a1', section_order: 2, item_order: 2 },
{ section: 'B', item: 'b1', section_order: 1, item_order: 2 },
{ section: 'A', item: 'a2', section_order: 2, item_order: 1 },
{ section: 'B', item: 'b2', section_order: 1, item_order: 1 }
];
data.sort((a, b) => (a.section_order - b.section_order) || (a.item_order - b.item_order));
var result = [];
for(var item of data){
var section = item.section;
if(!result[section]){ // if not exists => create new
result[section] = { section, items:[item] };
}else{ // if exists => add one more item into items
result[section].items.push(item);
}
}
console.log(Object.values(result));
Old version using reduce & map
const data = [
{ section: 'A', item: 'a1', section_order: 2, item_order: 2 },
{ section: 'B', item: 'b1', section_order: 1, item_order: 2 },
{ section: 'A', item: 'a2', section_order: 2, item_order: 1 },
{ section: 'B', item: 'b2', section_order: 1, item_order: 1 }
];
data.sort((a, b) => (a.section_order - b.section_order) || (a.item_order - b.item_order));
const accumData = data.reduce((accum, currElm) => {
const currSection = currElm['section'];
accum[currSection] = (accum[currSection] || []).concat(currElm);
return accum;
}, {});
var result = Object.entries(accumData).map(([key, value]) => ({section: key, items: value}));
console.log(result);
I have two array of objects, and I want to sum the object that have a same key (in this case, id), and if there is no match key, then just create a new one.. I'm sorry if I am not explaining it clearly, I am new to JavaScript/Array/Object thing...
var dataOne = [ { id:"1", total: 10, win: 5 }, { id:"2", total: 5, win: 1 }, { id:"3", total: 5, win: 2 } ]
and
var dataTwo = [ { id:"1", total: 5, win: 2 }, { id:"2", total: 2, win: 3 }, { id:"5", total: 5, win: 4 } ]
Expected result:
var combinedData = [ { id:"1", total: 15, win: 7 }, { id:"2", total: 7, win: 4 }, { id:"3", total: 5, win: 2 }, { id:"5", total: 5, win: 4 } ]
I have tried to use the solution from Sum all data in array of objects into new array of objects
but, apparently the type of data is kind of different
So, I tried to use this method from Javascript - Sum of two object with same properties
function sumObjectsByKey(...objs) {
for (var prop in n) {
if (acc.hasOwnProperty(prop)) acc[prop] += n[prop];
else acc[prop] = n[prop];
}
return acc;
}
and
var combinedData = sumObjectsByKey(dataOne, dataTwo);
But apparently, that method won't work for an array of objects.
I get
{0: "0[object Object][object Object]", 1: "0[object Object][object Object]", 2: "0[object Object][object Object]"}
as a result.
Combine both arrays by spread into Array.concat(). Reduce the items into a Map, while combining the current item, with the item that already exists in the Map. Convert back to array by spreading the Map.values() iterator:
// utility function to sum to object values (without the id)
const sumItem = ({ id, ...a }, b) => ({
id,
...Object.keys(a)
.reduce((r, k) => ({ ...r, [k]: a[k] + b[k] }), {})
});
const sumObjectsByKey = (...arrs) => [...
[].concat(...arrs) // combine the arrays
.reduce((m, o) => // retuce the combined arrays to a Map
m.set(o.id, // if add the item to the Map
m.has(o.id) ? sumItem(m.get(o.id), o) : { ...o } // if the item exists in Map, sum the current item with the one in the Map. If not, add a clone of the current item to the Map
)
, new Map).values()]
const dataOne = [ { id:"1", total: 10, win: 5 }, { id:"2", total: 5, win: 1 }, { id:"3", total: 5, win: 2 } ]
const dataTwo = [ { id:"1", total: 5, win: 2 }, { id:"2", total: 2, win: 3 }, { id:"5", total: 5, win: 4 } ]
const result = sumObjectsByKey(dataOne, dataTwo)
console.log(result)
I'd suggest Array.reduce here. In the body of the reduction function, if the id isn't in the result accumulator, add it, then increment all of the values for each property in the object.
var dataOne = [ { id:"1", total: 10, win: 5 }, { id:"2", total: 5, win: 1 }, { id:"3", total: 5, win: 2 } ]
var dataTwo = [ { id:"1", total: 5, win: 2 }, { id:"2", total: 2, win: 3 }, { id:"5", total: 5, win: 4 } ]
var sumObjectsByKey = (...objs) =>
Object.values(objs.reduce((a, e) => {
a[e.id] = a[e.id] || {id: e.id};
for (const k in e) {
if (k !== "id") {
a[e.id][k] = a[e.id][k] ? a[e.id][k] + e[k] : e[k];
}
}
return a;
}, {}))
;
console.log(sumObjectsByKey(...dataOne, ...dataTwo));