Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Group by and sum array of hashes in javascript

Tags:

javascript

I have following array of hashes and want to convert it into an array like the one at the bottom of the post.

var responseData = [
  {deviceType: "Smartphone", deviceCount: 14},
  {deviceType: "Tablet", deviceCount: 11},
  {deviceType: "Notebook", deviceCount: 3},
  {deviceType: "Desktop", deviceCount: 2},
  {deviceType: "Smartphone", deviceCount: 1},
  {deviceType: "Tablet", deviceCount: 10},
  {deviceType: "Notebook", deviceCount: 30},
  {deviceType: "Desktop", deviceCount: 20}
];

function dataMapper(responseData){
  let series = [];
  if(responseData && responseData.length){
  responseData.forEach(function(resource){
  existingElement = series.filter(function (item) {
      return item.deviceType === resource.deviceType;
    });
  if (existingElement) {
    deviceCount = existingElement[0].deviceCount + resource.deviceCount;
    existingElement[0].deviceCount = deviceCount
  }else{
    series[0].push({deviceType: resource.deviceType, y: resource.deviceCount});
  }
    });
  }
  return series
}

console.log(dataMapper(responseData))

I want to convert this into:

var expectedResult = [
    {deviceType: "Smartphone", deviceCount: 15},
    {deviceType: "Tablet", deviceCount: 21},
    {deviceType: "Notebook", deviceCount: 33},
    {deviceType: "Desktop", deviceCount: 22}
];
like image 635
Gol. D Roger Avatar asked Feb 15 '26 23:02

Gol. D Roger


2 Answers

Using an ES6 Map and reduce:

const responseData = [{deviceType: "Smartphone", deviceCount: 14},{deviceType: "Tablet", deviceCount: 11},{deviceType: "Notebook", deviceCount: 3},{deviceType: "Desktop", deviceCount: 2},{deviceType: "Smartphone", deviceCount: 1},{deviceType: "Tablet", deviceCount: 10},{deviceType: "Notebook", deviceCount: 30},{deviceType: "Desktop", deviceCount: 20}];

const result = Array.from(
    responseData.reduce( 
        (acc, o) => (acc.get(o.deviceType).deviceCount += o.deviceCount, acc),
        new Map(responseData.map( ({deviceType}) => [deviceType, {deviceType, deviceCount: 0} ] )) 
    ).values()
);

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
like image 183
trincot Avatar answered Feb 18 '26 13:02

trincot


Its much easier if you use a hashtable and build up the result in parallel:

 const hash = {}, result = [];

for(const {deviceType, deviceCount} of responseData){
  if(hash[deviceType]){
     hash[deviceType].deviceCount += deviceCount;
  } else {
     result.push(hash[deviceType] = {deviceType, deviceCount});
  }
}

If you really want to iterate over the array, you should use find instead of filter:

const result = [];

for(const {deviceType, deviceCount} of responseData){
  const exists = result.find(device => device.deviceType === deviceType);
 if(exists){
   exists.deviceCount += deviceCount;
  } else {
   result.push({deviceType, deviceCount });
  }
}
like image 24
Jonas Wilms Avatar answered Feb 18 '26 11:02

Jonas Wilms



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!