I find this paragraph slightly confusing since it uses the word group but we never actually use d3.group afterwards. Is it possible to do grouping with d3.group and then somehow roll that up? I often get the feeling I'd like to have the original elements around (like when using d3.group) but then i also want to rollup a couple different ways.
d3.rollup “rolls up” the groups computed by d3.group. You can do that by hand yourself if you want by using d3.group instead of d3.rollup, but then you have to know how deep the hierarchy is: is it a single-level, double-level, triple-level group etc.?
For example, if you have a single-level group, then d3.group returns a Map from key to array of elements. If you want to rollup that Map, then it’s new Map(Array.from(d3.group(data, (d) => d.key), ([key, elements]) => [key, aggregate(elements)])). But if you have a double-level group, then d3.group returns a Map from key to Map from key to array of elements, etc.
There isn’t a separate d3.rollup that you can apply to a Map returned by d3.group because that Map isn’t self-describing: it doesn’t retain its height (number of levels) or key functions. However, the aggregate function you pass to d3.rollup can compute multiple aggregates if you want to rollup the same group in multiple ways — nothing says that your aggregate function needs to return a number. In fact, d3.group is just a special case of d3.rollup where the aggregate function is the identity function.
https://github.com/d3/d3-array/blob/master/src/group.js
🤯 that group is just reduce with identity, I somehow had it conceptually backwards and that makes a lot of sense. Also thank you for the clear explanation of why it can't be the other way around.
I'd like to reword the above paragraph to incorporate some of your explanation, as well as attempt an example of multiple aggregates below.
When using d3.rollup, you get a Map from sport to sum of earnings; with d3.group, you get a Map from sport to array of athletes. So in both cases d3.least is returning the least entry in the Map, but in one case the entry’s value is a number (computed via d3.rollup’s reducer), and the other it’s an array (computed by d3.group).
ah ok, that makes sense, I think I was confused by the wording "You can do the same with d3.group, of course." Here the definition of same is specific to getting the smallest group. As I re-read it I see that its correct, but I think also seeing d3.sum used in both made my mind jump to the idea that they'd have the same return value