Reputation: 55
I have next data:
const data = [
{amount: 100, percent: 1, days: 7},
{amount: 75, percent: 3, days: 8},
{amount: 75, percent: 3, days: 3},
{amount: 100, percent: 2, days: 5},
{amount: 100, percent: 1, days: 10},
{amount: 50, percent: 3, days: 9}
];
The task is to group objects by amount and percent, so that if amount and percent in different objects are the same I need to add their days. The result should look the next way:
const data = [
{amount: 100, percent: 1, days: 17},
{amount: 75, percent: 3, days: 11},
{amount: 100, percent: 2, days: 5},
{amount: 50, percent: 3, days: 9}
];
1st and 3rd objects are not grouped because of different percent. I have tried to use reduce method:
const result = data.reduce((groupedByAmount, current) => {
let amount = current.amount;
let percent= current.percent;
if (amount == amount && percent == percent) {
groupedByAmount.amount = amount;
current.days += current.days
}
return groupedByAmount
}, {
amount: 0,
percent: null,
days: 0
});
I don't how to check if amount and percent are the same, maybe map or filter would help
Upvotes: 2
Views: 218
Reputation: 672
const data = [
{amount: 100, percent: 1, days: 7},
{amount: 75, percent: 3, days: 8},
{amount: 75, percent: 3, days: 3},
{amount: 100, percent: 2, days: 5},
{amount: 100, percent: 1, days: 10},
{amount: 50, percent: 3, days: 9}
];
const doGroup = (data) => {
const obj = data.reduce((result, next) => {
const key = `${next.amount}_${next.percent}`
const dd = result[key]?.days ?? 0;
result[key] = {...next, days: next.days + dd};
return result;
}, {});
return Object.values(obj);
}
console.log(doGroup(data))
Upvotes: 1
Reputation: 136
This example is larger in number of lines, but simpler, perhaps.
const data = [
{amount: 100, percent: 1, days: 7},
{amount: 75, percent: 3, days: 8},
{amount: 75, percent: 3, days: 3},
{amount: 100, percent: 2, days: 5},
{amount: 100, percent: 1, days: 10},
{amount: 50, percent: 3, days: 9}
];
function group_by_amount_percent(array) {
var ret = []
var cache = {}
array.forEach(function(e, i, a) {
if (cache[e.amount] == null) { cache[e.amount] = {} }
if (cache[e.amount][e.percent] == null) { cache[e.amount][e.percent] = 0 }
cache[e.amount][e.percent] += e.days
})
for (var amount in cache) {
for (var percent in cache[amount]) {
ret.push({amount: amount, percent: percent, days: cache[amount][percent]})
}
}
return ret
}
console.log('group_by_amount_percent(data): ', group_by_amount_percent(data))
Upvotes: 0
Reputation: 28611
Considering each of the methods you've suggested:
reduce
=> reduce array elements to a single value. Can be used to create an object, then convert that object back to the array
map
=> return a value for every value in the array
filter
=> return multiple (or single) matching values
You can loop through each value, building a new array and using filter()
to find existing values to add to.
Note: this likely won't perform well with large arrays due to the multiple use of .filter()
- using a composite key (combining two values into a single value) would likely perform better.
const data = [
{amount: 100, percent: 1, days: 7},
{amount: 75, percent: 3, days: 8},
{amount: 75, percent: 3, days: 3},
{amount: 100, percent: 2, days: 5},
{amount: 100, percent: 1, days: 10},
{amount: 50, percent: 3, days: 9}
];
var result = [];
data.forEach(e => {
var current = result.filter(d => d.amount == e.amount && d.percent == e.percent);
if (current.length === 0) {
result.push(e);
} else {
current[0].days += e.days;
}
});
console.log(result);
Upvotes: 1
Reputation: 943
const data = [
{amount: 100, percent: 1, days: 7},
{amount: 75, percent: 3, days: 8},
{amount: 75, percent: 3, days: 3},
{amount: 100, percent: 2, days: 5},
{amount: 100, percent: 1, days: 10},
{amount: 50, percent: 3, days: 9}
];
const temp = data.reduce((acc, {amount, percent, days}) => {
acc[amount] ||= {}
acc[amount][percent] ||= 0
acc[amount][percent] += days
return acc;
}
,{});
const result = Object.entries(temp).reduce((acc, [amount, obj]) => {
acc.push(...Object.entries(obj).map(([percent, days]) => ({ amount: Number(amount), percent: Number(percent), days })))
return acc
},[])
console.log(result)
Upvotes: 0