Max
Max

Reputation: 55

need to group objects, in array of objects, in one group

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

Answers (4)

Jafar Jabr
Jafar Jabr

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

Zlatov
Zlatov

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

fdomn-m
fdomn-m

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

bel3atar
bel3atar

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

Related Questions