Looks OK.
Though I have to ask why you're using map
, when you're not really mapping the array to a new array. Using reduce
would be more semantically correct, but in this case even just replacing map
with forEach
would also be more accurate. (The difference is literally only skin-deep; there's zero change in overall functionality.)
I might ask why an undefined value should throw an exception, though. It'll work fine without it, and I might want to group objects based on whether or not they have a certain property or not. Without the exception, I'd be able to get back an object with some of the elements grouped by the key "undefined"
And if I were super nit-picky, I'd say you should always using braces even for one-line "block" like your throw
line.
I'm betting, though, that a lot of the time, you'll want to group by a simple, named key, in which case it'd be much easier to pass in a string, rather than a function. A custom function is still very useful, though, so it'd be nice to support both.
I might do:
function groupBy(array, keyOrIterator) {
var iterator, key;
// use the function passed in, or create one
if(typeof key !== 'function') {
key = String(keyOrIterator);
iterator = function (item) { return item[key]; };
} else {
iterator = keyOrIterator;
}
return array.reduce(function (memo, item) {
var key = iterator(item);
memo[key] = memo[key] || [];
memo[key].push(item);
return memo;
}, {});
}
Lastly: Libraries like underscore.js and it's "doppelgänger" lo-dash has this and many other helpful functions, ready for you to use. I'm only mentioning it because if you found yourself needed a groupBy
function, you'll probably find yourself needing other similar functions, and libraries like those provide that in spades.