Reputation: 6464
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?
Upvotes: 0
Views: 793
Reputation: 25187
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:
[].reduce(function(prev, curr, i, arr) {});// <-- function is the only param
When used with a single param, the behavior is that the first time the function is executed, i
equals 1 (not 0), and prev
and curr
are 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:
[].reduce(function(prev, curr, i, arr) {}, { foo:'bar' });// <-- 2nd param {foo:bar}
it does actually call the function, with the first call passing i
equal to 0 and prev
equaling { 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 that values
is always 2 elements, which will cause an issue if it's longer).
Check if group.length == 1
and if so, return group
, instead of calling reduce.
Upvotes: 1