0

I have a react component with a state that looks like this:

this.state = {
            categoryGroups: [
                {
                    groupName: 'Immediate Obligations',
                    budgeted: '5,000.00',
                    activity: '3,275.76',
                    subcategories: [
                        {
                            category: 'food',
                            budgeted: '500.00',
                            activity: '300.76'
                        },
                        {
                            category: 'rent',
                            budgeted: '1,000.00',
                            activity: '1,000.00'
                        }
                    ]
                },
                {
                    groupName: 'True Expenses',
                    budgeted: '2,000.00',
                    activity: '1,000.33',
                    subcategories: [
                        {
                            category: 'Car Insurance',
                            budgeted: '60.00',
                            activity: '60.00'
                        },
                        {
                            category: 'Gas',
                            budgeted: '100.00',
                            activity: '34.50'
                        }
                    ]
                }
            ]
        }

I want to find the total budgeted amount for all of the subcategories in each category group. How can I do this?

stepup.stepout
  • 61
  • 1
  • 1
  • 9
  • Possible duplicate of [Better way to sum a property value in an array (Using Angularjs)](https://stackoverflow.com/questions/23247859/better-way-to-sum-a-property-value-in-an-array-using-angularjs) – James Dec 04 '17 at 22:57
  • it would be helpful if you would add your desired output for the input you provided. – Potter Dec 04 '17 at 23:06
  • It'd be good if you posted what you've tried too. – fubar Dec 04 '17 at 23:36

2 Answers2

1

You could achieve this with a simple for-loop. JavaScript offers some nice functions on arrays, though.

See Mozilla's Documentation.

For summing things up, Array.prototype.reduce comes to mind. You can use it e.g. as follows:

this.state.categoryGroups.reduce(sumCategoryGroups, 0);

function sumCategoryGroups(sum, categoryGroup) {
    return sum + categoryGroup.subcategories.reduce(sumSubCategories, 0);
}

function sumSubCategories(sum, subCategory) {
    return sum + subCategory.budgeted;
}

edit: As I didn't recognize that the budgeted amount is stored as a String, the above solution probably wouldn't do what the user who asked the question intended it to.

Depending on how certain you can be that the number-String is always formatted the same way, you could use something like the following:

function budgetToNumber(budgetString) {
    return Number(budgetString.replace(/,/g, ''));
}

With the prior code changing to:

this.state.categoryGroups.reduce(sumCategoryGroups, 0);

function sumCategoryGroups(sum, categoryGroup) {
    return sum + categoryGroup.subcategories.reduce(sumSubCategories, 0);
}

function sumSubCategories(sum, subCategory) {
    return sum + budgetToNumber(subCategory.budgeted);
}

Notice though, that there are quite a few ways this could be dangerous to do; i.e. when the format of the budget amount changes.

JanS
  • 2,065
  • 3
  • 27
  • 29
  • 1
    It's probably worth mentioning for the sake of the user with the question that their currency amounts are stored in strings, so using the `+` operator might not have the effect they intend :) – Rich Churcher Dec 04 '17 at 23:16
  • 1
    `[ '1', '2', '3' ].reduce((acc, n) => acc + n, 0) // '0123'` – Rich Churcher Dec 04 '17 at 23:18
  • 1
    You're absolutely right. I didn't notice that - thanks! I'll update the answer. – JanS Dec 04 '17 at 23:19
1

You could map each subcategory and reduce the two as so:

const categoryGroups = [{
    groupName: 'Immediate Obligations',
    budgeted: '5,000.00',
    activity: '3,275.76',
    subcategories: [{
        category: 'food',
        budgeted: '500.00',
        activity: '300.76'
      },
      {
        category: 'rent',
        budgeted: '1,000.00',
        activity: '1,000.00'
      }
    ]
  },
  {
    groupName: 'True Expenses',
    budgeted: '2,000.00',
    activity: '1,000.33',
    subcategories: [{
        category: 'Car Insurance',
        budgeted: '60.00',
        activity: '60.00'
      },
      {
        category: 'Gas',
        budgeted: '100.00',
        activity: '34.50'
      }
    ]
  }
];

const subCategories = categoryGroups.map(({ subcategories }) => {
  return subcategories.reduce((prev, { budgeted }) => {
    return +prev['budgeted'].replace(/,/g, '') +  +budgeted.replace(/,/g, '');
  });
});

const total = subCategories.reduce((prev, next) => prev + next);

console.log(total);
Carl Edwards
  • 13,826
  • 11
  • 57
  • 119