I recently posted this question about summing arrays in JavaScript using d3.nest()
I got a good solution (two in fact), but it turns out both have an issue when adapted to append additional information:
data = [
{
continent: 'africa',
country: 'gabon',
values: [1, 2]
}, {
continent: 'africa',
country: 'chad',
values: [3, 4]
}, {
continent: 'asia',
country: 'china',
values: [1, 2]
}
];
sum_by = 'continent';
rollupAgg = function(data, sum_by) {
return d3.nest().key(function(d) {
return d[sum_by];
}).rollup(function(group) {
return group.reduce(function(prev, cur, index, arr) {
return {
values: prev.values.map(function(d, i) {
return d + cur.values[i];
}),
sum_by: sum_by // additional information
};
});
}).entries(data);
};
reduce() doesn’t run if there is only one row in that group, so this returns the following:
[
{
"key": "africa",
"values": {
"values": [4, 6],
"sum_by": "continent"
}
}, {
"key": "asia",
"values": {
"continent": "asia",
"country": "china", // country information shouldn't have been retained
"values": [1, 2]
} // sum_by information should have been added
}
];
Can you see a way to modify this function so that it returns the desired result?
Hasn’t occurred to me till now that a single element array will not execute the function; but it makes sense, because you’re using with a single param:
When used with a single param, the behavior is that the first time the function is executed,
iequals 1 (not 0), andprevandcurrare the first and second elements of the array. Since you only have one element, there’s no way to call it in this form.If you use reduce with a 2nd param:
it does actually call the function, with the first call passing
iequal to 0 andprevequaling{ foo:'bar' }.So I guess you have 2 options:
Either modify it to pass a 2nd param, which in your case would need to be
{ values:[0,0] }(and that hardcodes the fact thatvaluesis always 2 elements, which will cause an issue if it’s longer).Check if
group.length == 1and if so,return group, instead of calling reduce.