0

I'm working with an array on React and i'm trying to filter it by month and year, i managed to do it by month but for some reason i can't add the year key, this is what i have so far:

This is the array that i have originally:

paid = [
 {amount:155, month:11, year:2020, date:11-11-2020}
 {amount:120, month:11, year:2021, date:05-11-2021}
 {amount:135, month:12, year:2020, date:11-12-2020}
...
]

const group = groupBy(d, (invoices) => invoices.month); //d is the array called "paid"

This is the groupBy function:

function groupBy(list, keyGetter) {
    const map = new Map();
    list.forEach((item) => {
      const key = keyGetter(item);
      const collection = map.get(key);
      if (!collection) {
        map.set(key, [parseInt(item.amount)]);
      } else {
        collection.push(parseInt(item.amount));
      }
    });
    return map;
  }

And this is the result i have:

grouped = [
 {name:11, values: [155,120...]},
 {name:12, values: [135...]
];

And what i want to to is to also have it grouped by the year, so for example, the month 11, shouldn't have two values, because on the original array i have on month that's 11 from 2020 and one from 2021, so what i want to have as a result is this:

grouped = [
 {name:11/2020, values: [155...]},
 {name:11/2021, values: [120...]},
 {name:12/2020, values: [135...]
];

Can anyone help me with this?

3
  • 2
    Then adjust/fix keyGetter() so it returns a value consisting of year and month Commented Mar 9, 2021 at 13:11
  • If i do this const group = groupBy(d, (invoices) => [ invoices.month, invoices.year]); i get this as a result: grouped = [ {[name: '11', '2020'], [value: '155', '155', '11/11/2020']}...] and all the registers separated, they don't group, it creates an array for every register with the month and year as an array called name Commented Mar 9, 2021 at 13:21
  • 1
    This would work with an object but not with a Map. Make the key a string and you're done. Commented Mar 9, 2021 at 13:40

2 Answers 2

1

If I understand correctly you want to sum all values per month per year. I guess this will work.

// Generate random data.
const genData = () => {
  const d = [];
  for(let i =0; i < 1000; i++) {
    d.push({
      year: Math.round(Math.random() * 10) + 2001,
      month: Math.round(Math.random() * 12),
      amount: Math.round(Math.random() * 100) + 100
    })
  }
  return d;
};

// Sum all data per month per year
const sumData = (d) => {
  const summed = {};
  for(const {year,month,amount} of d) {
    // By using a unique key for each year/month combi you can easily access the
    // intermedeiate result and add another value.
    const key = year + '/' + month;
    
    // If it does not yet exist, create an empty record for this year/month
    if(!(key in summed)) {
      summed[key] = {year,month, sum:0, values:[]};
    }
    
    // Grab the intermediate values and add amount to sum and to values
    summed[key].values.push(amount)
    summed[key].sum += amount;
  }
  return Object.values(summed);
};

// Run all
const d = genData();
console.log(d);
console.log(sumData(d));
Sign up to request clarification or add additional context in comments.

Comments

1

Working with Array.reduce method could be more simple, for the example I added some values:

const paid = [
 {amount:155, month:11, year:2020, date:'11-11-2020'},
 {amount:160, month:11, year:2020, date:'11-11-2020'},
 {amount:120, month:11, year:2021, date:'05-11-2021'},
 {amount:130, month:11, year:2021, date:'05-11-2021'},
 {amount:135, month:12, year:2020, date:'11-12-2020'},
 {amount:145, month:12, year:2020, date:'11-12-2020'}
]
const grouped = paid.reduce((acc,val)=>{
    if(acc[val.month+'/'+val.year]){
        acc[val.month+'/'+val.year].push(val.amount)
    } else {
        acc[val.month+'/'+val.year] = [val.amount]
    }
    return acc
}, {})
console.log(JSON.stringify(grouped,null,2))

EDIT -----------------
I edited the code to use the group by function and to produce an array containing the values and the sum. you can group passing an array containing first level key (like ['month'] or ['month', 'year']):

const paid = [
  { amount: 155, month: 11, year: 2020, date: "11-11-2020" },
  { amount: 160, month: 11, year: 2020, date: "11-11-2020" },
  { amount: 120, month: 11, year: 2021, date: "05-11-2021" },
  { amount: 130, month: 11, year: 2021, date: "05-11-2021" },
  { amount: 135, month: 12, year: 2020, date: "11-12-2020" },
  { amount: 145, month: 12, year: 2020, date: "11-12-2020" }
];

const groupBy = (data, keys) => {
  return Object.values(
    data.reduce((acc, val) => {
      const name = keys.reduce((finalName,key)=> finalName + val[key]+'/','').slice(0, -1)
      if (acc[name]) {
        acc[name].values.push(val.amount);
        acc[name].sum += val.amount;
      } else {
        acc[name] = {
          name,
          sum:val.amount,
          values:[val.amount]
        };;
      }
      return acc;
    }, {})
  );
};

console.log(JSON.stringify(groupBy(paid, ['month','year']), null, 2));

2 Comments

Yes, i was actually using reduce to to the sum, but i didn't put it in the post because that was not what i was struggling with, but thank you for your answer!
hello @delv123 I just edited my answer to better fit your need

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.