javascript | Object grouping

Try with something like this:

function groupBy(collection, property) {
    var i = 0, val, index,
        values = [], result = [];
    for (; i < collection.length; i++) {
        val = collection[i][property];
        index = values.indexOf(val);
        if (index > -1)
            result[index].push(collection[i]);
        else {
            values.push(val);
            result.push([collection[i]]);
        }
    }
    return result;
}

var obj = groupBy(list, "group");

Keep in mind that Array.prototype.indexOf isn't defined in IE8 and older, but there are common polyfills for that.


Reduce is great for situations like this. Given list below is your input data:

const list = [{
    'name': 'Display',
    'group': 'Technical detals',
    'id': '60',
    'value': '4'
  },
  {
    'name': 'Manufacturer',
    'group': 'Manufacturer',
    'id': '58',
    'value': 'Apple'
  },
  {
    'name': 'OS',
    'group': 'Technical detals',
    'id': '37',
    'value': 'Apple iOS'
  }
];

const groups = list.reduce((groups, item) => {
  const group = (groups[item.group] || []);
  group.push(item);
  groups[item.group] = group;
  return groups;
}, {});

console.log(groups);

And if you wanted to be immutable, you could write the reduce like this:

const list = [{
    'name': 'Display',
    'group': 'Technical detals',
    'id': '60',
    'value': '4'
  },
  {
    'name': 'Manufacturer',
    'group': 'Manufacturer',
    'id': '58',
    'value': 'Apple'
  },
  {
    'name': 'OS',
    'group': 'Technical detals',
    'id': '37',
    'value': 'Apple iOS'
  }
];

const groups = list.reduce((groups, item) => ({
  ...groups,
  [item.group]: [...(groups[item.group] || []), item]
}), {});

console.log(groups);

Depending on whether your environment allows the spread syntax.


If you like working with ES6 Map, then this is for you:

function groupBy(arr, prop) {
    const map = new Map(Array.from(arr, obj => [obj[prop], []]));
    arr.forEach(obj => map.get(obj[prop]).push(obj));
    return Array.from(map.values());
}

const data = [{ name: "Display", group: "Technical detals", id: 60, value: 4 }, { name: "Manufacturer", group: "Manufacturer", id: 58, value: "Apple" }, { name: "OS", group: "Technical detals", id: 37, value: "Apple iOS" }];
	
console.log(groupBy(data, "group"));
.as-console-wrapper { max-height: 100% !important; top: 0; }

The Map instance is created from key/value pairs that are generated from the input array. The keys are the values of the property to group by, and the values are initialised as empty arrays.

Then those arrays are populated. Finally the values of the map (i.e. those populated arrays) are returned.


If you're using underscore.js in your application then you can simply do the following:

var groups = _.groupBy(data, 'group'); // data is your initial collection

Or if you prefer not to use any library then you can do it yourself:

var groups = { };
data.forEach(function(item){
   var list = groups[item.group];

   if(list){
       list.push(item);
   } else{
      groups[item.group] = [item];
   }
});

You can see both examples in action http://jsfiddle.net/nkVu6/3/