Home > Back-end >  How to sum values in object with nested arrays?
How to sum values in object with nested arrays?

Time:11-01

I have the following structure:

groupedData = {
   rice: [
     {
       name: 'white rice'
       quantity: 2
       category: 'rice'
     },
     {
      name: 'brown rice'
      quantity: 1
      category: 'rice'
    }
   ],
   water: [
     {
       name: 'sparkle water'
       quantity: 1
       category: 'water'
     },
     {
      name: 'still water'
      quantity: 1
      category: 'water'
    }
   ],
   tea: [{
       name: 'green tea'
       quantity: 1
       category: 'water'
   }],
 }

What I want to achieve is to have a summed quantity of each category, so as: rice: 3, water: 2, tea: 1

I tried the following:

  const sum = () => {
    let quantity = []
    for (var property in groupedData) {
      for (let i=0; i< groupedData[property].length; i  ){
      quantity[property] = groupedData[property][i].quantity;
      }
    }
    return quantity;
}

but it doesn't return summed data but only the quantity of the first item [rice: 2, water: 1, tea: 1]

CodePudding user response:

This is based on your question.

const groupedData = {
  rice: [{
      name: 'white rice',
      quantity: 2,
      category: 'rice',
    },
    {
      name: 'brown rice',
      quantity: 1,
      category: 'rice',
    }
  ],
  water: [{
      name: 'sparkle water',
      quantity: 1,
      category: 'water',
    },
    {
      name: 'still water',
      quantity: 1,
      category: 'water',
    }
  ],
  tea: [{
    name: 'green tea',
    quantity: 1,
    category: 'water',
  }],
}

const sum = () => {
  let quantity = {}
  for (var property in groupedData) {
    for (let i = 0; i < groupedData[property].length; i  ) {
      quantity = {
        ...quantity,
        [property]: quantity[property] ? quantity[property]   groupedData[property][i].quantity :  groupedData[property][i].quantity
      }
    }
  }
  return quantity;
}

console.log(sum());
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

And this is my answer with reduce

const groupedData = {
  rice: [{
      name: 'white rice',
      quantity: 2,
      category: 'rice',
    },
    {
      name: 'brown rice',
      quantity: 1,
      category: 'rice',
    }
  ],
  water: [{
      name: 'sparkle water',
      quantity: 1,
      category: 'water',
    },
    {
      name: 'still water',
      quantity: 1,
      category: 'water',
    }
  ],
  tea: [{
    name: 'green tea',
    quantity: 1,
    category: 'water',
  }],
}

const sum = () => {
  let res = {}
  for (var props in groupedData) {
    const item = groupedData[props].reduce((acc, cur) => {
      acc  = cur.quantity;
      return acc;
    }, 0);
    res[props] = item;
  }
  return res;
}

console.log(sum());
<iframe name="sif2" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

CodePudding user response:

You can do something like this:

const result = Object.entries(groupedData).reduce((prev, [k, v]) => {
  const sums = {
    ...prev,
    [k]: v.reduce((p, c) => p   c.quantity, 0),
  }
  return sums
}, {})

Here is the full snippet:

const groupedData = {
  rice: [{
      name: 'white rice',
      quantity: 2,
      category: 'rice',
    },
    {
      name: 'brown rice',
      quantity: 1,
      category: 'rice',
    },
  ],
  water: [{
      name: 'sparkle water',
      quantity: 1,
      category: 'water',
    },
    {
      name: 'still water',
      quantity: 1,
      category: 'water',
    },
  ],
  tea: [{
    name: 'green tea',
    quantity: 1,
    category: 'water',
  }, ],
}

const result = Object.entries(groupedData).reduce((prev, [k, v]) => {
  const sums = {
    ...prev,
    [k]: v.reduce((p, c) => p   c.quantity, 0),
  }
  return sums
}, {})

console.log(result)
<iframe name="sif3" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

CodePudding user response:

Your solution does not add the nodes. Just add the quantity of each node

const groupedData = {
  rice: [
    { name: 'white rice', quantity: 2, category: 'rice' },
    { name: 'brown rice', quantity: 1, category: 'rice' }
  ],
  water: [
    { name: 'sparkle water', quantity: 1, category: 'water' },
    { name: 'still water', quantity: 1, category: 'water' }
  ],
  tea: [
    { name: 'green tea', quantity: 1, category: 'water' }],
};

const sum = () => {
  let quantity = {}
  for (var property in groupedData) {
    for (let i = 0; i < groupedData[property].length; i  ) {
      quantity[property] = quantity[property] ? quantity[property] : 0;
      quantity[property]  = groupedData[property][i].quantity;
    }
  }
  return quantity;
};
console.log(sum());
<iframe name="sif4" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

You can also make use of Object.entries, Array.forEach and Array.reduce to achieve this.

const groupedData = {
  rice: [
    { name: 'white rice', quantity: 2, category: 'rice' },
    { name: 'brown rice', quantity: 1, category: 'rice' }
  ],
  water: [
    { name: 'sparkle water', quantity: 1, category: 'water' },
    { name: 'still water', quantity: 1, category: 'water' }
  ],
  tea: [
    { name: 'green tea', quantity: 1, category: 'water' }],
};
const sum = () => {
  let quantity = {};
  Object.entries(groupedData).forEach(([key, value]) => {
    quantity[key] = value.reduce((acc, { quantity }) => acc  = quantity, 0)
  });
  return quantity;
};
console.log(sum());
<iframe name="sif5" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

CodePudding user response:

and as a one liner...

  var result = Object.keys(groupedData).reduce((prev, key) => ({...prev,[key]: groupedData[key].reduce((total,item)=>total item.quantity,0)}),{});
  console.log(result);

using Object.entries is perhaps more readable

  var result2 = Object.entries(groupedData).reduce((prev, [k, v]) => ({...prev, [k]: v.reduce((total,item)=>total item.quantity,0)}),{});
  console.log(result2);
  • Related