'use strict'; /** * Calculate the simple moving average of an array. A new array is returned with the average * of each range of elements. A range will only be calculated when it contains enough elements to fill the range. * * ```js * console.log(sma([1, 2, 3, 4, 5, 6, 7, 8, 9], 4)); * //=> [ '2.50', '3.50', '4.50', '5.50', '6.50', '7.50' ] * //=> │ │ │ │ │ └─(6+7+8+9)/4 * //=> │ │ │ │ └─(5+6+7+8)/4 * //=> │ │ │ └─(4+5+6+7)/4 * //=> │ │ └─(3+4+5+6)/4 * //=> │ └─(2+3+4+5)/4 * //=> └─(1+2+3+4)/4 * ``` * @param {Array} `arr` Array of numbers to calculate. * @param {Number} `range` Size of the window to use to when calculating the average for each range. Defaults to array length. * @param {Function} `format` Custom format function called on each calculated average. Defaults to `n.toFixed(2)`. * @return {Array} Resulting array of averages. * @api public */ function sma(arr, range, format) { if (!Array.isArray(arr)) { throw TypeError('expected first argument to be an array'); } var fn = typeof format === 'function' ? format : toFixed; var num = range || arr.length; var res = []; var len = arr.length + 1; var idx = num - 1; while (++idx < len) { res.push(fn(avg(arr, idx, num))); } return res; } /** * Create an average for the specified range. * * ```js * console.log(avg([1, 2, 3, 4, 5, 6, 7, 8, 9], 5, 4)); * //=> 3.5 * ``` * @param {Array} `arr` Array to pull the range from. * @param {Number} `idx` Index of element being calculated * @param {Number} `range` Size of range to calculate. * @return {Number} Average of range. */ function avg(arr, idx, range) { return sum(arr.slice(idx - range, idx)) / range; } /** * Calculate the sum of an array. * @param {Array} `arr` Array * @return {Number} Sum */ function sum(arr) { var len = arr.length; var num = 0; while (len--) num += Number(arr[len]); return num; } /** * Default format method. * @param {Number} `n` Number to format. * @return {String} Formatted number. */ function toFixed(n) { return n.toFixed(2); }