Tyler Zika Tyler Zika - 6 days ago 5
Javascript Question

Combine an array of objects and their properties. Remove object after combining

I need to merge the objects together. The

resource
property is what determines if the objects can be merged. To determine where the
hours
property values goes, the
billable
property is used. I want the array to look like this

members = [{billable: true, hours: 15, name: "Joe Smith", resource: "00530000003mgYGAAY", totalBillableHours: 20, totalHours: 25, totalNonBillableHours: 5},
{billable: false, hours: 5, name: "Jan Smith", resource: "00530000003mgYTAAY", totalBillableHours: 14, totalHours: 19, totalNonBillableHours: 10}]


The state of
billable
and
hours
properties for the final result is irrelevant.

Here's the code. Can't seem to figure out why it wont work.

http://codepen.io/anon/pen/MbOdmV?editors=0002

members = [
{billable: true, hours: 15, name: "Joe Smith", resource: "00530000003mgYGAAY", totalBillableHours: 0, totalHours: 0, totalNonBillableHours: 0},
{billable: true, hours: 5, name: "Joe Smith", resource: "00530000003mgYGAAY", totalBillableHours: 0, totalHours: 0, totalNonBillableHours: 0},
{billable: false, hours: 5, name: "Joe Smith", resource: "00530000003mgYGAAY", totalBillableHours: 0, totalHours: 0, totalNonBillableHours: 0},
{billable: false, hours: 5, name: "Jan Smith", resource: "00530000003mgYTAAY", totalBillableHours: 0, totalHours: 0, totalNonBillableHours: 0},
{billable: true, hours: 12, name: "Jan Smith", resource: "00530000003mgYTAAY", totalBillableHours: 0, totalHours: 0, totalNonBillableHours: 0},
{billable: true, hours: 2, name: "Jan Smith", resource: "00530000003mgYTAAY", totalBillableHours: 0, totalHours: 0, totalNonBillableHours: 0}
];

for (i = 0; i < members.length; i++) {
var member = members[i];

if (member.resource == members[i + 1].resource) {

if(member.billable == true) {
member.totalBillableHours += members[i + 1].hours;
}
else {
member.totalNonBillableHours += members[i + 1].hours;
}
member.totalHours += members[i + 1].hours;
members.splice(i + 1, 1);
--i;
if (members[i + 2] == undefined) {
break;
}

}
}
console.log(members);

Answer

It gets pretty tricky when you remove items from an array while iterating over it.

I've rewritten your solution in a more functional way here: http://codepen.io/tinacious/pen/gLXJow?editors=1011

var members = [
  {billable: true, hours: 15, name: "Joe Smith", resource: "00530000003mgYGAAY", totalBillableHours: 0, totalHours: 0, totalNonBillableHours: 0},
  {billable: true, hours: 5, name: "Joe Smith", resource: "00530000003mgYGAAY", totalBillableHours: 0, totalHours: 0, totalNonBillableHours: 0},
  {billable: false, hours: 5, name: "Joe Smith", resource: "00530000003mgYGAAY", totalBillableHours: 0, totalHours: 0, totalNonBillableHours: 0},
  {billable: false, hours: 5, name: "Jan Smith", resource: "00530000003mgYTAAY", totalBillableHours: 0, totalHours: 0, totalNonBillableHours: 0},
  {billable: true, hours: 12, name: "Jan Smith", resource: "00530000003mgYTAAY", totalBillableHours: 0, totalHours: 0, totalNonBillableHours: 0},
  {billable: true, hours: 2, name: "Jam Smith", resource: "00530000003mgYTAAY", totalBillableHours: 0, totalHours: 0, totalNonBillableHours: 0}  
];

function combineMembers(members) {
  var combinedMembers = {};

  members.forEach(function (member) {
    var resourceId = member.resource;
    var typeOfHour = member.billable ? 'totalBillableHours' : 'totalNonBillableHours';

    if (!combinedMembers[resourceId]) {
      combinedMembers[resourceId] = Object.assign({}, member);
    }

    combinedMembers[resourceId][typeOfHour] += member.hours;      
    combinedMembers[resourceId].totalHours += member.hours;
  });

  return Object.keys(combinedMembers).map(function (resourceId) {
    return combinedMembers[resourceId];
  });
}

console.log(combineMembers(members));

The resulting output is what you are looking for:

Array[2]
    0 : Object
        billable : true
        hours : 15
        name : "Joe Smith"
        resource : "00530000003mgYGAAY"
        totalBillableHours : 20
        totalHours : 25
        totalNonBillableHours : 5
        __proto__ : Object
    1 : Object
        billable : false
        hours : 5
        name : "Jan Smith"
        resource : "00530000003mgYTAAY"
        totalBillableHours : 14
        totalHours : 19
        totalNonBillableHours : 5
        __proto__ : Object
    length : 2
    __proto__ : Array[0]