Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Group by array and add field and sub array in main array

I have a heavy array like this:

[
  {Id: 1, Name: 'Red', optionName: 'Color'}, 
  {Id: 2, Name: 'Yellow', optionName: 'Color'},
  {Id: 3, Name: 'Blue', optionName: 'Color'},
  {Id: 4, Name: 'Green', optionName: 'Color'},
  {Id: 7, Name: 'Black', optionName: 'Color'},
  {Id: 8, Name: 'S', optionName: 'Size'},
  {Id: 11, Name: 'M', optionName: 'Size'},
  {Id: 12, Name: 'L', optionName: 'Size'},
  {Id: 13, Name: 'XL', optionName: 'Size'},
  {Id: 14, Name: 'XXL', optionName: 'Size'}
]

What I need to do is to group them by optionName and have two row in the main array like this:

[
  {
    Name: 'Color',
    Data:[{Id: 1, Name: 'Red'},
          {Id: 2, Name: 'Yellow'},
          {Id: 3, Name: 'Blue'},
          {Id: 4, Name: 'Green'},
          {Id: 7, Name: 'Black'}]
  }, {
    Name: 'Size',
    Data:[{Id: 8, Name: 'S'},
          {Id: 11, Name: 'M'},
          {Id: 12, Name: 'L'},
          {Id: 13, Name: 'XL'},
          {Id: 14, Name: 'XXL'}]
  }
]

How to do it in javascript?

like image 883
surendra Kandira Avatar asked Dec 30 '15 04:12

surendra Kandira


2 Answers

This is a snippet I wrote for these kind of situations. You can add this functionality to all of your arrays:

Object.defineProperty(Array.prototype, 'group', {
  enumerable: false,
  value: function (key) {
    var map = {};
    this.forEach(function (e) {
      var k = key(e);
      map[k] = map[k] || [];
      map[k].push(e);
    });
    return Object.keys(map).map(function (k) {
      return {key: k, data: map[k]};
    });
  }
});

You can use it like this. You can just pass a function which defines how you want to group your data.

var newArray = arr.group(function (item) {
  return item.optionName;
});

Working Fiddle

If you need, you can replace {key: k, data: map[k]} with {Name: k, Data: map[k]}.


This is also more compact ES6 version of the code above:

Object.defineProperty(Array.prototype, 'group', {
  enumerable: false,
  value: function (key) {
    let map = {};
    this.map(e => ({k: key(e), d: e})).forEach(e => {
      map[e.k] = map[e.k] || [];
      map[e.k].push(e.d);
    });
    return Object.keys(map).map(k => ({key: k, data: map[k]}));
  }
});

Use it like this:

let newArray = arr.group(item => item.optionName))
like image 124
Aᴍɪʀ Avatar answered Oct 10 '22 16:10

Aᴍɪʀ


An ES6 solution using Map object:

function groupBy(arr, key) {
  	return arr.reduce(
      (sum, item) => {
      	const groupByVal = item[key];
        groupedItems = sum.get(groupByVal) || [];
        groupedItems.push(item);
      	return sum.set(groupByVal, groupedItems);
        },
      new Map()
      );
}

var Data = [ 
{ Id: 1, Name: 'Red', optionName: 'Color' }, 
  { Id: 2, Name: 'Yellow', optionName: 'Color' },
  { Id: 3, Name: 'Blue', optionName: 'Color' },
  { Id: 4, Name: 'Green', optionName: 'Color' },
  { Id: 7, Name: 'Black', optionName: 'Color' },
  { Id: 8, Name: 'S', optionName: 'Size' },
  { Id: 11, Name: 'M', optionName: 'Size' },
  { Id: 12, Name: 'L', optionName: 'Size' },
  { Id: 13, Name: 'XL', optionName: 'Size' },
  { Id: 14, Name: 'XXL', optionName: 'Size' } ];

document.getElementById("showArray").innerHTML =JSON.stringify([...groupBy(Data, 'optionName')], null, 4); 
<pre id="showArray"></pre>
like image 25
Max Leizerovich Avatar answered Oct 10 '22 14:10

Max Leizerovich