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 | |
}; |
This comment has been minimized.
This comment has been minimized.
How would you introduce multiple keys to group by? |
This comment has been minimized.
This comment has been minimized.
this piece of code can do the job |
This comment has been minimized.
This comment has been minimized.
Thank you SO MUCH, for creating this readable version of the code. It helps me a lot.<3 |
This comment has been minimized.
This comment has been minimized.
Just spent significant amount of time trying to understand this before I noticed your comment in Stack Overflow. Very useful, Thank you! |
This comment has been minimized.
This comment has been minimized.
Thanks for sharing this! I've created another version that supports multiple keys https://gist.github.com/one89/395a3ffb2df4d0648ec7b0caf6cf5d37 |
This comment has been minimized.
This comment has been minimized.
Thank you for this. Very helpful |
This comment has been minimized.
This comment has been minimized.
I'm using a version of this that allows supplying any list of keys (granted that they're all strings). You can rewrite the function supplied to /**
* @param {any[]} arr
* @param {string[]} keys
*/
const groupBy = (arr, keys) => {
return arr.reduce((storage, item) => {
const objKey = keys.map(key => `${ item[key] }`).join(':'); //should be some unique delimiter that wont appear in your keys
if (storage[objKey]) {
storage[objKey].push(item);
} else {
storage[objKey] = [item];
}
return storage;
}, {});
}; |
This comment has been minimized.
This comment has been minimized.
It would be great to have a TypeScript version of this. |
This comment has been minimized.
This comment has been minimized.
@DarkLite1 This is how I've adapted it for TS use: const groupBy = <T>(arr: T[], keys: (keyof T)[]): { [key: string]: T[] } => {
return arr.reduce((storage, item) => {
const objKey = keys.map(key => `${ item[key] }`).join(':');
if (storage[objKey]) {
storage[objKey].push(item);
} else {
storage[objKey] = [item];
}
return storage;
}, {} as { [key: string]: T[] });
} |
This comment has been minimized.
This comment has been minimized.
Thank you for getting back to me. On StackOvelfow we posted the same question and got this answer: type ObjectKey = string | number | symbol
export const groupBy = <
K extends ObjectKey,
TItem extends Record<K, ObjectKey>
>(
items: TItem[],
key: K
): Record<ObjectKey, TItem[]> =>
items.reduce(
(result, item) => ({
...result,
[item[key]]: [...(result[item[key]] || []), item],
}),
{} as Record<ObjectKey, TItem[]>
) I'm still a noob, so I don't know which one is better but it works fine. The only thing to keep in mind is that the value for |
This comment has been minimized.
This comment has been minimized.
The answer you got on SO is more complete, mine is a more naive approach that assumes objects in the array have no nested objects internally and that keys are always strings, though the SO answer does restrict you to a single key (you can pretty easily change that to make the second argument into the function an array of keys or just do a spread of string values for all other function arguments). If you need this for a more simple use case you could use my approach which doesn’t require you to specify key typing |
This comment has been minimized.
This comment has been minimized.
thanks,really helpfull |
This comment has been minimized.
To make this more readable, I renamed the parameters, and split up one line into several to get a better model of what's happening.
I changed
(rv[x[key]] = rv[x[key]] || []).push(x);
to: