Skip to content

Instantly share code, notes, and snippets.

@robmathers
Created October 25, 2018 23:18
Show Gist options
  • Select an option

  • Save robmathers/1830ce09695f759bf2c4df15c29dd22d to your computer and use it in GitHub Desktop.

Select an option

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
};
@jose2007kj
Copy link
Copy Markdown

thanks,really helpfull

@PolyUnityCTO
Copy link
Copy Markdown

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
Copy Markdown

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

@ryderwishart
Copy link
Copy Markdown

Thanks!

@Vinetos
Copy link
Copy Markdown

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
Copy Markdown

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