nyphur
nyphur

Reputation: 2886

How do I find the averages of similar objects in an array and output them into one object?

I have an array of objects with this structure:

    [
      costBreakdown: {
        flexMeetAncCost: "1,274,051",
        flexOneTimeCosts: "0",
        flexSeatCharges: "2,403,869",
        tradFacilMgmtCost: "134,437",
        tradOneTimeTotalCost: "1,462,049",
        tradRentCost: "1,572,738",
      },

      costBreakdown: {
        flexMeetAncCost: "1,279,524",
        flexOneTimeCosts: "0",
        flexSeatCharges: "2,414,197",
        tradFacilMgmtCost: "135,025",
        tradOneTimeTotalCost: "1,467,029",
        tradRentCost: "1,579,576",
      },
    ]

and I'm trying to iterate through all of these objects and find the average for every key after parsing the strings and to make it a whole number, then output one object of the aggregate.

const { mean } = require('lodash')

  const result = allLambdas.reduce((acc, currValue, index, array) => {
    const aggregateCostBreakdown = (key) => (
      Math.round(mean(array.map((obj) => parseFloat(obj.costBreakdown[key].replace(/,/g, ''))))).toLocaleString('en')
    )

    const avgCostBreakdown = {
      flexMeetAncCost: aggregateCostBreakdown('flexMeetAncCost'),
      flexOneTimeCosts: aggregateCostBreakdown('flexOneTimeCosts'),
      flexSeatCharges: aggregateCostBreakdown('flexSeatCharges'),
      tradFacilMgmtCost: aggregateCostBreakdown('tradFacilMgmtCost'),
      tradOneTimeTotalCost: aggregateCostBreakdown('tradOneTimeTotalCost'),
      tradRentCost: aggregateCostBreakdown('tradRentCost')
    }

    acc.costBreakdown = avgCostBreakdown

    return acc
  }, { 
      costBreakdown: {},
     }
    )

While this seemingly works, I don't think I should ever be referencing the array argument in the reduce function as this seems not performant.

How do I get the average of these array of objects and output them out into just one object?

Upvotes: 1

Views: 62

Answers (2)

Alex G
Alex G

Reputation: 1917

You can try something like this, where you first sum the values and keep the count and then you find the mean of each prop. Hope this helps.

const data = [{
    costBreakdown: {
        flexMeetAncCost: "1,274,051",
        flexOneTimeCosts: "0",
        flexSeatCharges: "2,403,869",
        tradFacilMgmtCost: "134,437",
        tradOneTimeTotalCost: "1,462,049",
        tradRentCost: "1,572,738",
    } },{
    costBreakdown: {
        flexMeetAncCost: "1,279,524",
        flexOneTimeCosts: "0",
        flexSeatCharges: "2,414,197",
        tradFacilMgmtCost: "135,025",
        tradOneTimeTotalCost: "1,467,029",
        tradRentCost: "1,579,576",
    },
    }
];

const findMeans = (arr) => {

    const summed = arr.reduce((acc, { costBreakdown }) => {

        Object.keys(costBreakdown).forEach((key) => {

            const n = parseFloat(costBreakdown[key].replace(',', '.'));

            acc.costBreakdown[key] = acc.costBreakdown[key] ? { value: acc.costBreakdown[key].value + n, count: acc.costBreakdown[key].count + 1 } : { value: n, count: 1 }
        });

        return acc;

    }, { costBreakdown: {} });

    return Object.keys(summed.costBreakdown).reduce((acc, val) => {

        acc.costBreakdown[val] = summed.costBreakdown[val].value / summed.costBreakdown[val].count;

        return acc;

    }, { costBreakdown: {} });
};

console.log(findMeans(data));

Upvotes: 1

Pehota
Pehota

Reputation: 116

If I understand correctly you need to reduce the array to an object of the same structure as the elements inside the array but the values for the properties in the resulting array should be the average of all co-responding props of the elements, right?

Might be something like this should work:

const convertToNumber = parseFloat; // make your own implementation
const allLambdasLength = allLambdas.length;

const result = allLambdas.reduce((acc, currValue, index) => {
    if(index < allLambdasLength - 1) {
        return {
            flexMeetAncCost: acc.flexMeetAncCost + convertToNumber(currValue.flexMeetAncCost),
            // do this for all keys in the object
            ...
        };
    } else {
      return {
          costBreakdown: {
            flexMeetAncCost: acc.flexMeetAncCost / allLambdasLength,
            // do this for all keys in the object
            ...
          }
      };
    }
}, {})

Upvotes: 0

Related Questions