I'm working on a custom reduce function to average values. My problem is that all of my data is currently in an array, and when I pass in v, it passes in that entire array. I need to access specific indices of v so that I can aggregate the data, but I am having issues with that.
var curIndex = 1;
function DefineGroups(dimension, dLen) {
var groups = [];
curIndex = 1;
for(var h = 0; h < dLen-3; h++) {
groups[h] = dimension.group().reduce(SetReduceAdd, SetReduceSub, SetReduceBase);
curIndex++;
}
groups[groups.length] = dimension.group().reduce(SetReduceAdd, SetReduceSub, SetReduceBase);
curIndex++;
groups[groups.length] = dimension.group().reduce(SetReduceAdd, SetReduceSub, SetReduceBase);
return groups;
}
function SetReduceAdd(p, v) {
p.timestamps += 1;
p.sum += v[curIndex];
p.total = p.sum / p.timestamps;
return p;
}
function SetReduceSub(p, v) {
p.timestamps -= 1;
p.sum -= v[curIndex];
p.total = p.timestamps ? p.sum / p.timestamps : 0
return p;
}
function SetReduceBase() {
return {timestamps: 0, sum: 0.0, total: 0.0};
}
The problem is that when these functions actually get called, curIndex has changed, however I'm not really sure how I can pass in curIndex so that it can be referenced as a local instance variable instead of a global one. My result with the current implementation is that all groups end up as copies of each other, the final set of data in the array.
I tried looking at the crossfilter code for the basic reduce function, however it is unclear how I could change it to reflect what I need to be done, as the passed in parameters for Add/Remove appear to be set.
Any thoughts in regards to this issue would be great, thanks in advance.
I think you're having the exact same problem you were having here, and the answer is the same as by Gordon, I believe.
Specifically, you need to enclose your scope like
function buildReduce(index) {
return function(p, v) {
p.timestamps += 1;
p.sum += v[index];
p.total = p.sum / p.timestamps;
return p;
};
}
then build your groups like
groups[h] = dimension.group().reduce(buildReduce(curIndex), ...)
This will ensure that each group created uses the value that curIndex had at the time the group was created.
A note on what is happening here:
'buildReduce' is a function that takes an argument 'index' and returns a new function that uses the value of 'index' internally. Every time 'buildReduce' is called, it returns a new function specific to that argument value. After 'buildReduce' is called, the only place that the variable 'index' exists is inside the function returned by 'buildReduce'.
That function returned by 'buildReduce' is called different things by different people. I call them closures. Here is a guide to how they work, with a bunch of examples: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Closures
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With