I have an array such as
let array = [
{
id: 1,
name: "Name A",
expenseAmount: 100
},
{
id: 1,
name: "Name A",
expenseAmount: 50
},
{
id: 3,
name: "Name B",
expenseAmount: 10
},
{
id: 3,
name: "Name B",
expenseAmount: 20
}
];
And I am looking for a solution, which condenses that array in such a manner, that all objects with the same id and name get summed by their expenseAmount, so that it results in:
let array_goal = [
{
id: 1,
name: "Name A",
expenseAmount: 150
},
{
id: 3,
name: "Name B",
expenseAmount: 30
}
];
Could you please help? Thanks!
Array.prototype.reduce is your friend for tasks like these.
Find a preexisting object with the same id and add to the expense amount, if you can't find it, make it yourself and add it to the output array.
let array = [{
id: 1,
name: "Name A",
expenseAmount: 100
},
{
id: 1,
name: "Name A",
expenseAmount: 50
},
{
id: 3,
name: "Name B",
expenseAmount: 10
},
{
id: 3,
name: "Name B",
expenseAmount: 20
}
];
const condenseArray = (arr) => {
return arr.reduce((out, {id, name, expenseAmount}) => {
let data = out.find(({id: _id}) => _id === id);
if (!data) {
const newData = {id, name, expenseAmount: 0};
out = [...out, newData];
data = newData;
}
data.expenseAmount += expenseAmount;
return out;
}, []);
};
console.log(condenseArray(array));
This is one possible solution:
const mergeIdSumExpenses = (arr = array) => (
Object.values(arr.reduce(
(fin, itm) => ({
...fin,
[itm.id]: {
...itm,
expenseAmount: (fin[itm.id]?.expenseAmount || 0) + itm.expenseAmount
}
}), {}
))
);
Explanation
.reduce to iterate through the array & generate result as an objectitm's id already exists in the aggregator fin,itm.expenseAmount to existing prop (key: itm.id)itm.id)Object.values() to extract only the values from resultant objectCode Snippet
let array = [{
id: 1,
name: "Name A",
expenseAmount: 100
},
{
id: 1,
name: "Name A",
expenseAmount: 50
},
{
id: 3,
name: "Name B",
expenseAmount: 10
},
{
id: 3,
name: "Name B",
expenseAmount: 20
}
];
const mergeIdSumExpenses = (arr = array) => (
Object.values(arr.reduce(
(fin, itm) => ({
...fin,
[itm.id]: {
...itm,
expenseAmount: (fin[itm.id]?.expenseAmount || 0) + itm.expenseAmount
}
}), {}
))
);
console.log(mergeIdSumExpenses());
First step
Use filter to group by id and name
Second step
const array = [
{id:1,name:"Name A",expenseAmount:100},
{id:1,name:"Name A",expenseAmount:50},
{id:1,name:"Name B",expenseAmount:100},
{id:3,name:"Name B",expenseAmount:10},
{id:3,name:"Name B",expenseAmount:20}
];
const unique = array
.filter((element, index, arr) => index === arr.findIndex(e => e.id == element.id && e.name == element.name))
.map(u => {
u.expenseAmount =
array
.filter(a => a.id == u.id && a.name == u.name)
.reduce((n, {expenseAmount}) => n + expenseAmount, 0);
return u;
});
console.log(unique);