Group objects by multiple properties in array then sum up their values

Use Array#reduce with a helper object to group similar objects. For each object, check if the combined shape and color exists in the helper. If it doesn't, add to the helper using Object#assign to create a copy of the object, and push to the array. If it does, add it's values to used and instances.

var arr = [{"shape":"square","color":"red","used":1,"instances":1},{"shape":"square","color":"red","used":2,"instances":1},{"shape":"circle","color":"blue","used":0,"instances":0},{"shape":"square","color":"blue","used":4,"instances":4},{"shape":"circle","color":"red","used":1,"instances":1},{"shape":"circle","color":"red","used":1,"instances":0},{"shape":"square","color":"blue","used":4,"instances":5},{"shape":"square","color":"red","used":2,"instances":1}];

var helper = {};
var result = arr.reduce(function(r, o) {
  var key = o.shape + '-' + o.color;
  
  if(!helper[key]) {
    helper[key] = Object.assign({}, o); // create a copy of o
    r.push(helper[key]);
  } else {
    helper[key].used += o.used;
    helper[key].instances += o.instances;
  }

  return r;
}, []);

console.log(result);

If you can use ES6, you use a Map to collect the values, and then convert it back to an array by spreading the Map#values:

const arr = [{"shape":"square","color":"red","used":1,"instances":1},{"shape":"square","color":"red","used":2,"instances":1},{"shape":"circle","color":"blue","used":0,"instances":0},{"shape":"square","color":"blue","used":4,"instances":4},{"shape":"circle","color":"red","used":1,"instances":1},{"shape":"circle","color":"red","used":1,"instances":0},{"shape":"square","color":"blue","used":4,"instances":5},{"shape":"square","color":"red","used":2,"instances":1}];

const result = [...arr.reduce((r, o) => {
  const key = o.shape + '-' + o.color;
  
  const item = r.get(key) || Object.assign({}, o, {
    used: 0,
    instances: 0
  });
  
  item.used += o.used;
  item.instances += o.instances;

  return r.set(key, item);
}, new Map).values()];

console.log(result);

Use this method to specify multiple properties:

 public static groupBy(array, f) {
       let groups = {};
       array.forEach(function (o) {
         var group = JSON.stringify(f(o));
         groups[group] = groups[group] || [];
         groups[group].push(o);
       });
    return Object.keys(groups).map(function (group) {
      return groups[group];
    })
 }

Call this method like:

var result = Utils.groupBy(arr, function (item) {
            return [item.shape, item.color];
          });

You could use a hash table and the keys for grouping same groups.

var array = [{ shape: 'square', color: 'red', used: 1, instances: 1 }, { shape: 'square', color: 'red', used: 2, instances: 1 }, { shape: 'circle', color: 'blue', used: 0, instances: 0 }, { shape: 'square', color: 'blue', used: 4, instances: 4 }, { shape: 'circle', color: 'red', used: 1, instances: 1 }, { shape: 'circle', color: 'red', used: 1, instances: 0 }, { shape: 'square', color: 'blue', used: 4, instances: 5 }, { shape: 'square', color: 'red', used: 2, instances: 1 }],
    hash = Object.create(null),
    grouped = [];
    
array.forEach(function (o) {
    var key = ['shape', 'color'].map(function (k) { return o[k]; }).join('|');
    
    if (!hash[key]) {
        hash[key] = { shape: o.shape, color: o.color, used: 0, instances: 0 };
        grouped.push(hash[key]);
    }
    ['used', 'instances'].forEach(function (k) { hash[key][k] += o[k]; });
});

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