Last active
October 3, 2018 14:28
-
-
Save FergusInLondon/df118082c6fe7ced96685280647db031 to your computer and use it in GitHub Desktop.
A little JS object for calculating rolling averages, complete with callbacks upon update.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Fergus In London - https://fergus.london - <[email protected]> | |
* | |
* Simple little function for calculating rolling averages, both simple and | |
* weighted. Example can be found on the GitHub Gist, or on my website. | |
* | |
* Do as you please, no rights reserved and no warranties provided. :) | |
*/ | |
/** | |
* Constructs a new RollingAverage object. | |
* | |
* @see roller.js | |
* @param Number Defaults to 10 | |
* @return Object | |
*/ | |
var RollingAverage = function(limit) { | |
// Instance Variables | |
var sorted = [], | |
points = [], | |
callbacks = [function(r) { | |
sorted = points.slice(0); // this is a clone. yeah. fuck javascript. | |
sorted.sort(); | |
}]; | |
// Set Defaults | |
limit = limit || 10; | |
/** | |
* Iterate through all callbacks and call them; works to the order of which | |
* the callbacks are set. | |
*/ | |
function runCallbacks() { | |
for (var i = 0; i < callbacks.length; i++) | |
callbacks[i](); | |
}; | |
// Public interface | |
var public = { | |
/** | |
* Retrieves the latest datapoint. | |
*/ | |
latest: function() { | |
var len = points.length; | |
return (len > 0) ? points[len - 1] : null; | |
}, | |
/** | |
* Sets a new callback, and binds the current context to it, allowing | |
* the callback to call the averaging methods. | |
*/ | |
onUpdate: function(cb) { | |
callbacks.push(cb.bind(public)); | |
}, | |
/** | |
* Pushes a new datapoint, whilst ensuring that the length of the stored | |
* datapoints adheres to the user supplied value. | |
*/ | |
push: function(val) { | |
points.push(val); | |
if (points.length > limit) points.shift(); | |
runCallbacks(); | |
}, | |
/** | |
* Averaging Function: Mean. | |
*/ | |
mean: function() { | |
return (function(sum, n) { | |
for (var i = 0; i < n; i++) | |
sum += points[i]; | |
return sum; | |
})(0, points.length) / points.length; | |
}, | |
/** | |
* Averaging Function: Median. | |
*/ | |
median: function() { | |
if ((sorted.length % 2) > 0) | |
return sorted[Math.ceil(sorted.length / 2)]; | |
return (sorted[sorted.length / 2] + sorted[(sorted.length / 2) + 1]) / 2; | |
}, | |
/** | |
* Averaging Function: Mode. | |
*/ | |
mode: function() { | |
return (function(currentGreatest, map) { | |
for (var i = 0; i < sorted.length; i++) { | |
map[sorted[i]] = map[sorted[i]] ? map[sorted[i]]++ : 1; | |
if (!map[currentGreatest] || map[sorted[i]] > map[currentGreatest]) | |
currentGreatest = sorted[i]; | |
} | |
return currentGreatest; | |
})(0, {}); | |
}, | |
/** | |
* Averaging Function: Range. | |
*/ | |
range: function() { | |
return sorted[sorted.length - 1] - sorted[0]; | |
}, | |
/** | |
* Computes a weighted/exponential average, arguably the most useful | |
* type for real-time/continuous data. | |
*/ | |
weightedAverage: function() { | |
return (function(sum, n, weightBase){ | |
for (var i=0; i<n; i++) | |
sum += points[i] * ((i+1) / weightBase); | |
return sum; | |
})(0, points.length, ((points.length * (points.length+1)) / 2)); | |
} | |
}; | |
return public; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Usage
Demonstration