2

I have an object with basically three important parameters I need to for total calculation. So for example my object is as below :

[
{'Id':1,'ResourceId':1,'StartDate':'01-01-2017','Hours':8,'TotalHrs':8},
{'Id':2,'ResourceId':1,'StartDate':'01-01-2017','Hours':4,'TotalHrs':4},
{'Id':3,'ResourceId':1,'StartDate':'01-03-2017','Hours':4,'TotalHrs':4},
{'Id':4,'ResourceId':1,'StartDate':'01-03-2017','Hours':4,'TotalHrs':4},
{'Id':5,'ResourceId':2,'StartDate':'01-01-2017','Hours':2,'TotalHrs':2},
{'Id':6,'ResourceId':2,'StartDate':'01-01-2017','Hours':4,'TotalHrs':4},
{'Id':7,'ResourceId':2,'StartDate':'01-03-2017','Hours':2,'TotalHrs':2},
]

So, currently the TotalHrs parameter is of the same value as the Hours parameter.

I want it to be total for a particular ResourceId and Startdate. i.e If in the array if the ResourceId and Startdate matches the TotalHrs parameter should be total of the value from Hours parameter.

So the final array becomes.

[
{'Id':1,'ResourceId':1,'StartDate':'01-01-2017','Hours':8,'TotalHrs':12},
{'Id':2,'ResourceId':1,'StartDate':'01-01-2017','Hours':4,'TotalHrs':12},
{'Id':3,'ResourceId':1,'StartDate':'01-03-2017','Hours':4,'TotalHrs':8},
{'Id':4,'ResourceId':1,'StartDate':'01-03-2017','Hours':4,'TotalHrs':8},
{'Id':5,'ResourceId':2,'StartDate':'01-01-2017','Hours':2,'TotalHrs':6},
{'Id':6,'ResourceId':2,'StartDate':'01-01-2017','Hours':4,'TotalHrs':6},
{'Id':7,'ResourceId':2,'StartDate':'01-03-2017','Hours':2,'TotalHrs':2},
]

Hence in the above example, ResourceId : 1 and StartDate : 01-01-2017 has two occurrences with Hours value as 8 and 4, so there TotalHrs becomes 8+4=12.

Also, I don't want to group by, I want the same number of elements in the resulting array but with an updated value for TotalHrs.

RomanPerekhrest
  • 88,541
  • 4
  • 65
  • 105
Mukta
  • 79
  • 1
  • 1
  • 7

3 Answers3

0

Short solution using Array.prototype.reduce() and Array.prototype.forEach() functions:

var data = [ {'Id':1,'ResourceId':1,'StartDate':'01-01-2017','Hours':8,'TotalHrs':8}, {'Id':2,'ResourceId':1,'StartDate':'01-01-2017','Hours':4,'TotalHrs':4}, {'Id':3,'ResourceId':1,'StartDate':'01-03-2017','Hours':4,'TotalHrs':4}, {'Id':4,'ResourceId':1,'StartDate':'01-03-2017','Hours':4,'TotalHrs':4}, {'Id':5,'ResourceId':2,'StartDate':'01-01-2017','Hours':2,'TotalHrs':2}, {'Id':6,'ResourceId':2,'StartDate':'01-01-2017','Hours':4,'TotalHrs':4}, {'Id':7,'ResourceId':2,'StartDate':'01-03-2017','Hours':2,'TotalHrs':2} ];

data.forEach(function (o) {
    o.TotalHrs = this[o.ResourceId + o.StartDate];
}, data.reduce(function (r, o) {
    var k = o.ResourceId + o.StartDate;
    (!r[k])? r[k] = o.TotalHrs : r[k] += o.TotalHrs;
    return r;
}, {}));

console.log(data);

var k = o.ResourceId + o.StartDate; - k here is a hash key string for grouping entries with same ResourceId and StartDate attributes

RomanPerekhrest
  • 88,541
  • 4
  • 65
  • 105
0

I suggest to use a temporary object, using the StartDate and ResourceId as hash key, that will store the hours. This algorithm providers O(n) time complexity.

var data = [{'Id':1,'ResourceId':1,'StartDate':'01-01-2017','Hours':8},{'Id':2,'ResourceId':1,'StartDate':'01-01-2017','Hours':4},{'Id':3,'ResourceId':1,'StartDate':'01-03-2017','Hours':4},{'Id':4,'ResourceId':1,'StartDate':'01-03-2017','Hours':4},{'Id':5,'ResourceId':2,'StartDate':'01-01-2017','Hours':2},{'Id':6,'ResourceId':2,'StartDate':'01-01-2017','Hours':4},{'Id':7,'ResourceId':2,'StartDate':'01-03-2017','Hours':2}];

function populateTotalHrs(collection) {
  var collectionByHash = {};
  collection.forEach(function(obj) {
    var hash = obj.ResourceId + '_' + obj.StartDate;
    collectionByHash[hash] = collectionByHash[hash] || 0;
    collectionByHash[hash] += obj.Hours;
  });
  collection.forEach(function(obj) {
    var hash = obj.ResourceId + '_' + obj.StartDate;
    obj.TotalHrs = collectionByHash[hash];
  });  
}

populateTotalHrs(data);
console.log(data);
Apostolidis
  • 114
  • 1
  • 3
0

You could use a hash table and group it temporary by ResourceId and StartDate.

var data = [{ Id: 1, ResourceId: 1, StartDate: '01-01-2017', Hours: 8, TotalHrs: 8 }, { Id: 2, ResourceId: 1, StartDate: '01-01-2017', Hours: 4, TotalHrs: 4 }, { Id: 3, ResourceId: 1, StartDate: '01-03-2017', Hours: 4, TotalHrs: 4 }, { Id: 4, ResourceId: 1, StartDate: '01-03-2017', Hours: 4, TotalHrs: 4 }, { Id: 5, ResourceId: 2, StartDate: '01-01-2017', Hours: 2, TotalHrs: 2 }, { Id: 6, ResourceId: 2, StartDate: '01-01-2017', Hours: 4, TotalHrs: 4 }, { Id: 7, ResourceId: 2, StartDate: '01-03-2017', Hours: 2, TotalHrs: 2 }];

data.forEach(function (hash) {
    return function (a) {
        var key = [a.ResourceId, a.StartDate].join('|');
        if (!hash[key]) {
            hash[key] = [a];
            return;
        }
        hash[key].push(a);
        hash[key][0].TotalHrs += a.Hours;
        hash[key].forEach(function (b) {
            b.TotalHrs = hash[key][0].TotalHrs;
        });
    };
}(Object.create(null)));

console.log(data);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392