0

From the object below, I wanted to sum up certain properties (fare+tax and com+agency) by their key group (1345, 2353) and updated it in the current array object.

var details = [{ 1345:[
                {route: 34, fare: 45, tax: 46, date: 46, com: 45, agency: 24, totalCost: 0, totalFee: 0}], 
               2353: [
                {route: 32, fare: 45, tax: 45, date: 56, com: 34, agency: 52, totalCost: 0, totalFee: 0}, 
                {route: 42, fare: 34, tax: 64, date: 34, com: 56, agency: 34, totalCost: 0, totalFee: 0}
              ]} 
             ]

expected output: updated details (totalCost and totalFee)

    1345: 
{ route: 34, fare: 45, .... totalCost: 91, totalFee: 69 }
    2353: 
{ route: 32, fare: 45, ... totalCost: 188, totalFee: 90 },
{ route: 42, fare: 34, ... totalCost: 188, totalFee: 176 }

totalCost = fare + tax and totalFee = com + agency

I tried to simplified the array objects and convert by using Object.entries(details[0]), then reduce to sum up the target properties.

Object.entries(details[0]).reduce((acc, curr) => (acc = acc + curr["fare"]+curr["tax"]), 0);

However, NaN was returned.

Would appreciate if anyone could show me how I can loop through each key group and sum up the target values and update it (totalCost and totalFee).

4
  • 1
    You should use Object.values instead of Object.entries, and also you don't need to assign a new value to acc. Commented Aug 30, 2022 at 14:07
  • Pretty sure that totalFee on 2353 is wrong (34 + 52 + 56 + 34) !== 90 Commented Aug 30, 2022 at 14:27
  • @kelly I tried changing Object.entries to .values and remove acc, but it still doesn't work. If possible, can you give me an example? **I have updated my question and expected output. Thanks alot! Commented Sep 5, 2022 at 10:21
  • @benbotto you're right! I was in a hurried and didn't realized that... Commented Sep 5, 2022 at 10:21

3 Answers 3

2

One way (of many) would be to use a simple sum function to sum up an arbitrary array of values:

function sum(...nums) {
  return nums.reduce((acc, val) => acc + val)
}

Next, sum up the totalCost/totalFee logic for each key group (1345 and 2353), and then apply the sums to each array entry:

for (const [key, vals] of Object.entries(details[0])) {
  vals.forEach((val, _, vals) => {
    val.totalFee  = sum(...vals.map(val => val.com + val.agency))
    val.totalCost = sum(...vals.map(val => val.fare + val.tax))
  })
}

Here's the whole shebang:

const details = [
  {
    1345: [
      {route: 34, fare: 45, tax: 46, date: 46, com: 45, agency: 24, totalCost: 0, totalFee: 0},
    ], 
    2353: [
      {route: 32, fare: 45, tax: 45, date: 56, com: 34, agency: 52, totalCost: 0, totalFee: 0}, 
      {route: 42, fare: 34, tax: 64, date: 34, com: 56, agency: 34, totalCost: 0, totalFee: 0},
    ],
  },
]

for (const [key, vals] of Object.entries(details[0])) {
  vals.forEach((val, _, vals) => {
    val.totalFee  = sum(...vals.map(val => val.com + val.agency))
    val.totalCost = sum(...vals.map(val => val.fare + val.tax))
  })
}

console.log(JSON.stringify(details, null, 2))

function sum(...nums) {
  return nums.reduce((acc, val) => acc + val)
}

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for the answer. If I just wanted to update the current array object 'details' (totalCost and totalFee) or create new object with the same properties structure as 'details' , how should I modified the function ? **Each keygroup(1345, 2353) contains multiple objects. Appreciate your help!
@hans1125 I've updated the code per your comment. Now the two totals are updated in the original details object.
2

We can do this using a few Array.reduce() calls, the end result should be as required.

For each key group, we'd use Object.entries() to get the key and value for the group.

const details = [{ 1345:[ {route: 34, fare: 45, tax: 46, date: 46, com: 45, agency: 24, totalCost: 0, totalFee: 0}], 2353: [ {route: 32, fare: 45, tax: 45, date: 56, com: 34, agency: 52, totalCost: 0, totalFee: 0}, {route: 42, fare: 34, tax: 64, date: 34, com: 56, agency: 34, totalCost: 0, totalFee: 0} ]} ]
         
const result = details.reduce((acc, group) => { 
    return Object.entries(group).reduce((acc, [key, routes] ) => {
        return routes.reduce((acc, { fare, tax, com, agency}) => { 
            acc[key] = acc[key] || {};
            acc[key].totalCost = (acc[key].totalCost || 0) + fare + tax;
            acc[key].totalFee = (acc[key].totalFee || 0) + com + agency;
            return acc;
        }, acc)
    }, acc)
}, {})

console.log('Result:', result)
.as-console-wrapper { max-height: 100% !important; }

I've updated here to include the original array under each key group, naming it 'routes', this could be changed to anything:

const details = [{ 1345:[ {route: 34, fare: 45, tax: 46, date: 46, com: 45, agency: 24, totalCost: 0, totalFee: 0}], 2353: [ {route: 32, fare: 45, tax: 45, date: 56, com: 34, agency: 52, totalCost: 0, totalFee: 0}, {route: 42, fare: 34, tax: 64, date: 34, com: 56, agency: 34, totalCost: 0, totalFee: 0} ]} ]

const result = details.reduce((acc, group) => { 
    return Object.entries(group).reduce((acc, [key, routes] ) => {
        return routes.reduce((acc, { fare, tax, com, agency}) => { 
            acc[key] = acc[key] || { routes };
            acc[key].totalCost = (acc[key].totalCost || 0) + fare + tax;
            acc[key].totalFee = (acc[key].totalFee || 0) + com + agency;
            return acc;
        }, acc)
    }, acc)
}, {})

console.log('Result:', result)
.as-console-wrapper { max-height: 100% !important; }

2 Comments

Thanks you! If I just wanted to update the current array object 'details' (totalCost and totalFee) or create new object with the same properties structure as 'details', how should I modified the function ? **Each keygroup(1345, 2353) contains multiple objects. Appreciate your help!
I've added another snippet to include the array under each key group as 'routes'. You could call this something else of course!
1

Expanding on the use of Object.values

var details = [{ 1345:[
                {route: 34, fare: 45, tax: 46, date: 46, com: 45, agency: 24, totalCost: 0, totalFee: 0}], 
               2353: [
                {route: 32, fare: 45, tax: 45, date: 56, com: 34, agency: 52, totalCost: 0, totalFee: 0}, 
                {route: 42, fare: 34, tax: 64, date: 34, com: 56, agency: 34, totalCost: 0, totalFee: 0}
              ]} 
             ]

Object.values(details).map(x => {
  details = {}
  let count = 0;
  for (let y of Object.values(x)) {
    y = y.reduce(function (a, b) {
      for (const key in b) {
        if (a[key]) {
          a[key] = a[key] + b[key]
        } else {
          a[key] = b[key];
        }
      }
      return a;
    }, {});
    y['totalCost'] = y['fare'] + y['tax']; 
    y['totalFee'] = y['com'] + y['agency'];
    let totalObj = {};
    totalObj['totalCost:'] = y['totalCost'];
    totalObj['totalFee:'] = y['totalFee'];
    details[`${Object.keys(x)[count]}`] = totalObj;
    count++;
  };
});

console.log(details);

2 Comments

Thanks alot! If I just wanted to update the current array object 'details' (totalCost and totalFee) or create new object with the same properties structure as 'details', how should I modified the function ? **Each keygroup(1345, 2353) contains multiple objects like in 'details'. Your help is appreciated!
That's a difficult one because you can have multiple objects in one key group - so would you want to add totalCost and totalFee to all details elements? If so that appears a bit counterintuitive since the totalCost and totalFee will not look as if they've been summed correctly.

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.