Skip to content

Instantly share code, notes, and snippets.

@robmathers
Created October 25, 2018 23:18
Show Gist options
  • Star 99 You must be signed in to star a gist
  • Fork 10 You must be signed in to fork a gist
  • Save robmathers/1830ce09695f759bf2c4df15c29dd22d to your computer and use it in GitHub Desktop.
Save robmathers/1830ce09695f759bf2c4df15c29dd22d to your computer and use it in GitHub Desktop.
A more readable and annotated version of the Javascript groupBy from Ceasar Bautista (https://stackoverflow.com/a/34890276/1376063)
var groupBy = function(data, key) { // `data` is an array of objects, `key` is the key (or property accessor) to group by
// reduce runs this anonymous function on each element of `data` (the `item` parameter,
// returning the `storage` parameter at the end
return data.reduce(function(storage, item) {
// get the first instance of the key by which we're grouping
var group = item[key];
// set `storage` for this instance of group to the outer scope (if not empty) or initialize it
storage[group] = storage[group] || [];
// add this item to its group within `storage`
storage[group].push(item);
// return the updated storage to the reduce function, which will then loop through the next
return storage;
}, {}); // {} is the initial value of the storage
};
@PolyUnityCTO
Copy link

This was very helpful. Here's my version, which supports multiple keys in case the property you want to group by is deeper in the data structure:

// Takes an array of objects and the property by which they should be grouped.
// Produces an object of arrays keyed by the specified property values.
// 
// Provide multiple keys if your data is nested:   groupBy(dogs, 'values', 'emoji')
// 
// Ex: [{id: 1, group: 'A'}, {id: 2, group: 'B'}, {id: 3, group: 'A'}],   'group'
//     =>
//     {A: [{id: 1, group: 'A'}, {id: 3, group: 'A'}], B: [{id: 2, group: 'B'}]}
export const groupBy = (data, ...keys) =>
{
	// Ex: {values: {color: 'red'}}, ['values', 'color'] => 'red'
	const getGroupFromItem = (item, keys) =>
	{
		return (keys.length > 1)
			? getGroupFromItem(item[keys[0]], keys.slice(1))
			: item[keys[0]]
	}
	
	return data.reduce((results, item) =>
		{
			// Get the first instance of the key by which we're grouping
			var group = getGroupFromItem(item, keys);
			
			// Ensure that there's an array to hold our results for this group
			results[group] = results[group] || [];
			
			// Add this item to the appropriate group within results
			results[group].push(item);
			
			// Return the updated results object to be passed into next reduce call
			return results; 
		},
		
		// Initial value of the results object
		{}
	);
};

@AndreasHerz
Copy link

thank you all for these great solutions. Really helped me 😄

@ryderwishart
Copy link

Thanks!

@Vinetos
Copy link

Vinetos commented Jun 7, 2022

A simple version with a supplier for the groups

const groupBy = (arr, keysSupplier) => {
    return arr.reduce((obj, elt) => {
        let key = keysSupplier(elt)
        if (obj[key] === undefined)
            obj[key] = []
        obj[key].push(elt)
        return obj
    }, {})
}

// Example
// Grouping array by typeof
groupBy(array, elt => typeof elt)

@yogithesymbian
Copy link

yogithesymbian commented Oct 11, 2022

i looking for these outputs
[
{
   custom: 'data1 custom b',
   group_by: 'school x',
   "children": {
       // data
   }
},
{
   custom: 'data2 custom a',
   group_by: 'school a',
   "children": {
       // data
   }
},
]

but the unexpected is

'school a': {
  // data
 },
'school x': {
  // data
}

i have tried with

storage['data'] = storage['data'] || [];
    storage[group] = storage[group] || [];

    // add this item to its group within `storage`
    storage[group].push(item);

    // storage['data'].push({
    //   label: group,
    //   mode: 'span',
    //   html: false,
    //   children: storage[group]
    // });

but its looping the result.

i have solved by add new function look like these

exports.groupByVue = async function(data)  {
  let result = [];
  for (const key in data) {
    if (Object.hasOwnProperty.call(data, key)) {
      const element = data[key];
      result.push({
        label: key,
        children: element,
      })
    }
  }
  return result;
}

but i want the code is inside the group by as default .

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment