Skip to content

Instantly share code, notes, and snippets.

@leofavre
Last active January 6, 2023 06:11
Show Gist options
  • Save leofavre/370d5be92fa862cd94f9de81a3e1b0ca to your computer and use it in GitHub Desktop.
Save leofavre/370d5be92fa862cd94f9de81a3e1b0ca to your computer and use it in GitHub Desktop.
Similar to LoDash groupBy(), but with nested groups.
/**
* Part of [Canivete](http://canivete.leofavre.com/#deepgroupby)
*
* Groups the contents of an array by one or more iteratees.
* Unlike Lodash [`groupBy()`](https://lodash.com/docs/4.17.4#groupBy),
* this function can create nested groups, but cannot receive
* strings for iteratees.
*/
const deepGroupBy = (collection, ...iteratees) => {
let paths = collection.map(value => iteratees.map(iteratee => iteratee(value))),
result = {};
paths.forEach((path, index) => {
let currentValue = _simpleAt(result, path) || [],
newValue = currentValue.concat([collection[index]]);
_simpleSet(result, path, newValue);
});
return result;
};
const _isPlainObject = arg =>
arg != null && typeof arg == "object" && arg.constructor == Object;
const _parsePath = path =>
Array.isArray(path) ? path : `${path}`.split(".");
const _simpleAt = (obj, path) =>
_parsePath(path).reduce((obj, key) => {
return (obj != null && obj.hasOwnProperty(key)) ? obj[key] : undefined;
}, obj);
const _simpleSet = (obj, path, value) =>
_parsePath(path).reduce((obj, key, index, arr) => {
let isLast = (index === arr.length - 1);
if (!obj.hasOwnProperty(key) || (!isLast && !_isPlainObject(obj[key]))) {
obj[key] = {};
}
return (!isLast) ? obj[key] : obj[key] = value;
}, obj);
export default deepGroupBy;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment