Home > Enterprise >  Sum values of objects with same keys
Sum values of objects with same keys

Time:06-22

I have a data structure like this one. It's basiccally an array of objects.

const dataset = [
  {
    a: { total: 2, name: "red" },
    b: { total: 3, name: "gold" },
    c: { total: 6, name: "rose" },
  },
  {
    a: { total: 10, name: "red" },
    b: { total: 7, name: "purple" },
  },
  {
    a: { total: 1, name: "pink" },
    b: { total: 14, name: "blue" },
    c: { total: 10, name: "rose" },
  },
  {
    b: { total: 2, name: "green" },
    c: { total: 18, name: "rose" },
  },
]

This is what I would like to compute as result:

const result = { 
  a: 13, 
  b: 26, 
  c: 34, 
}

So, I need a sum of values total by objects with same key.I try to explain myself using the previous example:

const result = { 
  a: 13, // 2   10   1
  b: 26, // 3   7   14   2
  c: 34, // 6   10   18
}

Note that the keys a, b, c can be a lot (not only 3) and I don't know their name because they are dynamic.

How can I do that? I thought to group the objects {total, name} by keys and then sum by total but how? Is there a Lodash function that can help me?

CodePudding user response:

It's pretty simple, iterate over the dataset, then iterate over all keys in the dataset's row:

const dataset = [
  { a: { total: 2, name: "red" }, b: { total: 3, name: "gold" }, c: { total: 6, name: "rose" } },
  { a: { total: 10, name: "red" }, b: { total: 7, name: "purple" } },
  { a: { total: 1, name: "pink" }, b: { total: 14, name: "blue" }, c: { total: 10, name: "rose" } },
  { b: { total: 2, name: "green" }, c: { total: 18, name: "rose" } },
];

const result = {};
dataset.forEach(row => {
  for (let key in row) {
    if (!result[key])
      result[key] = 0;
    result[key]  = row[key].total;
  }
});

console.log(result);

CodePudding user response:

Why not use reduce with for of:

const dataset = [{a: { total: 2, name: "red" }, b: { total: 3, name: "gold" }, c: { total: 6, name: "rose" }, }, {a: { total: 10, name: "red" }, b: { total: 7, name: "purple" }, }, {a: { total: 1, name: "pink" }, b: { total: 14, name: "blue" }, c: { total: 10, name: "rose" }, }, {b: { total: 2, name: "green" }, c: { total: 18, name: "rose" }, }, ];

const result = dataset.reduce((res, cur) => {
    for (const [key, value] of Object.entries(cur)) {
      res[key] = (res[key] || 0)   value.total;
    }
    return res;
}, {});

console.log(result);

CodePudding user response:

You can use array reduce :

const dataset = [
  {
    a: { total: 2, name: "red" },
    b: { total: 3, name: "gold" },
    c: { total: 6, name: "rose" }
  },
  {
    a: { total: 10, name: "red" },
    b: { total: 7, name: "purple" }
  },
  {
    a: { total: 1, name: "pink" },
    b: { total: 14, name: "blue" },
    c: { total: 10, name: "rose" }
  },
  {
    b: { total: 2, name: "green" },
    c: { total: 18, name: "rose" }
  }
];
function getCount() {
  return dataset.reduce((countObj, nextVal) => {
    Object.keys(nextVal).forEach(key => {
      if(countObj[key]){
        countObj[key]  = nextVal[key].total;
      }else{
        countObj[key] = nextVal[key].total;
      }
    });
    return countObj;
  }, {});
}
console.log(getCount());

CodePudding user response:

Idea

Build a dictionary of totals, adding entries as you encounter properties for the first time.

Implementation

Iterate over items in your dataset, for each item iterate over the object properties.

Assumption: Each item object has a property total holding a number.

function tally ( pa_dataset ) {
    let dict_totals = {}
      ;
      
    pa_dataset.forEach ( po_record => {
        Object.entries(po_record).forEach ( pa_entry => {
            let s_key   = pa_entry[0]
              , x_value = pa_entry[1]
              ;
              
            if (!dict_totals.hasOwnProperty(s_key)) { dict_totals[s_key] = 0; }
            dict_totals[s_key]  = x_value.total;
        });
    });
    
    return dict_totals;
} // tally

// Test
const dataset = [
  {
    a: { total: 2, name: "red" },
    b: { total: 3, name: "gold" },
    c: { total: 6, name: "rose" },
  },
  {
    a: { total: 10, name: "red" },
    b: { total: 7, name: "purple" },
  },
  {
    a: { total: 1, name: "pink" },
    b: { total: 14, name: "blue" },
    c: { total: 10, name: "rose" },
  },
  {
    b: { total: 2, name: "green" },
    c: { total: 18, name: "rose" },
  },
];

console.log ( 'Totals:' );
console.log ( tally(dataset));

Remarks

There is no lodash function specifically implementing the desired functionality.

CodePudding user response:

const map = new Map()
dataset.forEach(obj=>{
    Object.keys(obj).forEach(key=>{
        const value = obj[key]
        if(value?.total){
            if(!map.has(key)){
                map.set(key,0)
            }
            map.set(key,map.get(key) value.total)
        }
    })
})

map.forEach((v,k)=>{
    console.log(`${k}:${v}`)
})
  • Related