Adrian Miesikowski
Adrian Miesikowski

Reputation: 9

Sum each row in object group by row

I need to sum minutes and seconds_left and group by id_project.

0: {id_project: 2, minutes: 12, seconds_left: NaN}
1: {id_project: 3, minutes: 15, seconds_left: 11}
2: {id_project: 4, minutes: 0, seconds_left: 11}
3: {id_project: 5, minutes: 0, seconds_left: 2}
4: {id_project: 0, minutes: 0, seconds_left: NaN}
5: {id_project: 1, minutes: 0, seconds_left: NaN}
6: {id_project: 4, minutes: 200, seconds_left: 6}
7: {id_project: 6, minutes: 43, seconds_left: NaN}
8: {id_project: 5, minutes: 100, seconds_left: NaN}
9: {id_project: 2, minutes: 123, seconds_left: NaN}
10: {id_project: 3, minutes: 454, seconds_left: NaN}
11: {id_project: 2, minutes: 89, seconds_left: NaN}
12: {id_project: 5, minutes: 23, seconds_left: NaN}
13: {id_project: 4, minutes: 0, seconds_left: NaN}
14: {id_project: 4, minutes: 11, seconds_left: NaN}
15: {id_project: 3, minutes: 66, seconds_left: NaN}
16: {id_project: 1, minutes: 676, seconds_left: NaN}

I thought of map & reduce, but I can't do this.

Is there any solution to my problem?

Thanks for answers :)

Upvotes: 0

Views: 88

Answers (4)

F.Almeida
F.Almeida

Reputation: 413

First off all ditch the NaN or convert them to 0 before execution, otherwise arithmetics will all have NaN value. Now here's what i did: I created a function to map your array into a new object with unique project IDs, where each one has the total sum of minutes and seconds:

var arr = [
    { id_project: 2, minutes: 12, seconds_left: 1 },
    { id_project: 3, minutes: 15, seconds_left: 11 },
    { id_project: 4, minutes: 0, seconds_left: 11 },
    { id_project: 5, minutes: 0, seconds_left: 2 },
    { id_project: 0, minutes: 0, seconds_left: 2 },
    { id_project: 1, minutes: 0, seconds_left: 3 },
    { id_project: 4, minutes: 200, seconds_left: 6 },
    { id_project: 6, minutes: 43, seconds_left: 3 },
    { id_project: 5, minutes: 100, seconds_left: 3 },
    { id_project: 2, minutes: 123, seconds_left: 10 },
    { id_project: 3, minutes: 454, seconds_left: 2 },
    { id_project: 2, minutes: 89, seconds_left: 2 },
    { id_project: 5, minutes: 23, seconds_left: 3 },
    { id_project: 4, minutes: 0, seconds_left: 4 },
    { id_project: 3, minutes: 66, seconds_left: 5 },
    { id_project: 1, minutes: 676, seconds_left: 5 }
];

var _flatten = function (arr) {
    var struct = {}; // We'll use a new flattened structure.
    var len = arr.length;
    for (var i = 0; i < len; i++) {
        var pID = arr[i].id_project;
        if (undefined !== struct[pID] && null !== struct[pID]) {
            // Already assigned. Sum minutes and seconds to already existing values.
            struct[pID].sum =
                struct[pID].sum +
                (arr[i].minutes * 60) +
                arr[i].seconds_left;
        }
        else {
            // Current project ID has not been assigne to new structure. Assign.
            struct[pID] = { sum: (arr[i].minutes * 60) + arr[i].seconds_left };
        }
    }
    return struct;
}

The output (sum is in seconds):

_flatten(arr);

0 : {sum: 2}
1 : {sum: 40568}
2 : {sum: 13453}
3 : {sum: 32118}
4 : {sum: 12021}
5 : {sum: 7388}
6 : {sum: 2583}

Upvotes: 1

HMR
HMR

Reputation: 39250

The following would do what you ask for, you can use map and reduce. I only use map for replacing NaN with 0 and reduce twice, once to get total seconds and once to create hours, minutes, seconds object:

var tmpTotal = [
  {id_project: 2, minutes: 12, seconds_left: NaN}
  ,{id_project: 3, minutes: 15, seconds_left: 11}
  ,{id_project: 4, minutes: 0, seconds_left: 11}
  ,{id_project: 5, minutes: 0, seconds_left: 2}
  ,{id_project: 0, minutes: 0, seconds_left: NaN}
  ,{id_project: 1, minutes: 0, seconds_left: NaN}
  ,{id_project: 4, minutes: 200, seconds_left: 6}
  ,{id_project: 6, minutes: 43, seconds_left: NaN}
  ,{id_project: 5, minutes: 100, seconds_left: NaN}
  ,{id_project: 2, minutes: 123, seconds_left: NaN}
  ,{id_project: 3, minutes: 454, seconds_left: NaN}
  ,{id_project: 2, minutes: 89, seconds_left: NaN}
  ,{id_project: 5, minutes: 23, seconds_left: NaN}
  ,{id_project: 4, minutes: 0, seconds_left: NaN}
  ,{id_project: 4, minutes: 11, seconds_left: NaN}
  ,{id_project: 3, minutes: 66, seconds_left: NaN}
  ,{id_project: 1, minutes: 676, seconds_left: NaN}
]
.map(//set seconds_left to 0 when NaN
  item=>
    isNaN(item.seconds_left)
      ? Object.assign({},item,{seconds_left:0})
      : item
)
.reduce(//group totals by id
  (acc,item)=>{
    acc[item.id_project]=acc[item.id_project] || {sum:0};
    acc[item.id_project].sum = 
      acc[item.id_project].sum + item.minutes * 60;
    acc[item.id_project].sum = 
      acc[item.id_project].sum + item.seconds_left;
    return acc;
  }
  ,{}
);
console.log(
  JSON.stringify(
    Object.keys(tmpTotal)//create hours,minutes,seconds from sum object
    .reduce(
      (acc,key)=>{
        acc[key] = {
          hours: Math.floor(tmpTotal[key].sum/3600),
          minutes: Math.floor((tmpTotal[key].sum%3600)/60),
          seconds: tmpTotal[key].sum%60
        }
        return acc;
      }
      ,{}
    )
    ,undefined
    ,2
  )
);

Upvotes: 0

Nina Scholz
Nina Scholz

Reputation: 386560

You could take a hash table as reference to the objects with same id_project and collect all values for the result.

var array = [{ id_project: 2, minutes: 12, seconds_left: NaN }, { id_project: 3, minutes: 15, seconds_left: 11 }, { id_project: 4, minutes: 0, seconds_left: 11 }, { id_project: 5, minutes: 0, seconds_left: 2 }, { id_project: 0, minutes: 0, seconds_left: NaN }, { id_project: 1, minutes: 0, seconds_left: NaN }, { id_project: 4, minutes: 200, seconds_left: 6 }, { id_project: 6, minutes: 43, seconds_left: NaN }, { id_project: 5, minutes: 100, seconds_left: NaN }, { id_project: 2, minutes: 123, seconds_left: NaN }, { id_project: 3, minutes: 454, seconds_left: NaN }, { id_project: 2, minutes: 89, seconds_left: NaN }, { id_project: 5, minutes: 23, seconds_left: NaN }, { id_project: 4, minutes: 0, seconds_left: NaN }, { id_project: 4, minutes: 11, seconds_left: NaN }, { id_project: 3, minutes: 66, seconds_left: NaN }, { id_project: 1, minutes: 676, seconds_left: NaN }],
    temp = {},
    result = [];

array.forEach(function (o) {
    if (!temp[o.id_project]) {
        temp[o.id_project] = { id_project: o.id_project, minutes: 0, seconds_left: 0 };
        result.push(temp[o.id_project]);
    }
    temp[o.id_project].minutes += o.minutes || 0;
    temp[o.id_project].seconds_left += o.seconds_left || 0;
});

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 1

Flavien Marianacci
Flavien Marianacci

Reputation: 149

If you can iterate over this array, create a new object containing the sum of your array

Something like this

var myArray = [{id_project: 2, minutes: 12, seconds_left: 30},{id_project: 2, minutes: 12, seconds_left: 50},{id_project: 3, minutes: 12, seconds_left: 12}]
var result = {};
myArray.forEach(function (element) {
  if (!result.hasOwnProperty(element.id_project))
    result[element.id_project] = {minutes : 0, seconds_left : 0};
  result[element.id_project].minutes += element.minutes;
  result[element.id_project].seconds_left += element.seconds_left;
});
    
console.log(result);

Upvotes: 0

Related Questions