If you don't strictly need to use the previous known sales figure, you can use a nice kind of spline interpolation for the sales figures:
/* Fritsch-Carlson monotone cubic spline interpolation
Usage example:
var f = createInterpolant([0, 1, 2, 3], [0, 1, 4, 9]);
var message = '';
for (var x = 0; x <= 3; x += 0.5) {
var xSquared = f(x);
message += x + ' squared is about ' + xSquared + '\n';
}
alert(message);
*/
var createInterpolant = function(xs, ys) {
var i, length = xs.length;
// Deal with length issues
if (length != ys.length) { throw 'Need an equal count of xs and ys.'; }
if (length === 0) { return function(x) { return 0; }; }
if (length === 1) {
// Impl: Precomputing the result prevents problems if ys is mutated later and allows garbage collection of ys
// Impl: Unary plus properly converts values to numbers
var result = +ys[0];
return function(x) { return result; };
}
// Rearrange xs and ys so that xs is sorted
var indexes = [];
for (i = 0; i < length; i++) { indexes.push(i); }
indexes.sort(function(a, b) { return xs[a] < xs[b] ? -1 : 1; });
var oldXs = xs, oldYs = ys;
// Impl: Creating new arrays also prevents problems if the input arrays are mutated later
xs = []; ys = [];
// Impl: Unary plus properly converts values to numbers
for (i = 0; i < length; i++) { xs.push(+oldXs[indexes[i]]); ys.push(+oldYs[indexes[i]]); }
// Get consecutive differences and slopes
var dys = [], dxs = [], ms = [];
for (i = 0; i < length - 1; i++) {
var dx = xs[i + 1] - xs[i], dy = ys[i + 1] - ys[i];
dxs.push(dx); dys.push(dy); ms.push(dy/dx);
}
// Get degree-1 coefficients
var c1s = [ms[0]];
for (i = 0; i < dxs.length - 1; i++) {
var m = ms[i], mNext = ms[i + 1];
if (m*mNext <= 0) {
c1s.push(0);
} else {
var dx = dxs[i], dxNext = dxs[i + 1], common = dx + dxNext;
c1s.push(3*common/((common + dxNext)/m + (common + dx)/mNext));
}
}
c1s.push(ms[ms.length - 1]);
// Get degree-2 and degree-3 coefficients
var c2s = [], c3s = [];
for (i = 0; i < c1s.length - 1; i++) {
var c1 = c1s[i], m = ms[i], invDx = 1/dxs[i], common = c1 + c1s[i + 1] - m - m;
c2s.push((m - c1 - common)*invDx); c3s.push(common*invDx*invDx);
}
// Return interpolant function
return function(x) {
// The rightmost point in the dataset should give an exact result
var i = xs.length - 1;
if (x == xs[i]) { return ys[i]; }
// Search for the interval x is in, returning the corresponding y if x is one of the original xs
var low = 0, mid, high = c3s.length - 1;
while (low <= high) {
mid = Math.floor(0.5*(low + high));
var xHere = xs[mid];
if (xHere < x) { low = mid + 1; }
else if (xHere > x) { high = mid - 1; }
else { return ys[mid]; }
}
i = Math.max(0, high);
// Interpolate
var diff = x - xs[i], diffSq = diff*diff;
return ys[i] + c1s[i]*diff + c2s[i]*diffSq + c3s[i]*diff*diffSq;
};
};
That can be used with the following code to do what you wanted:
var monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
var fromMonthNumber = function(monthNumber) {
return monthNames[monthNumber % 12] + ' ' + ((monthNumber / 12) | 0);
};
var toMonthNumber = function(monthName) {
var date = new Date(Date.parse(monthName));
return 12*date.getFullYear() + date.getMonth();
};
var interpolateSales = function(sales, months, range) {
var f = createInterpolant(months.map(toMonthNumber), sales);
var resultSales = [], resultMonths = [];
var firstMonth = toMonthNumber(range[0]), lastMonth = toMonthNumber(range[1]);
for (var x = firstMonth; x <= lastMonth; x++) {
resultSales.push(Math.round(f(x)));
resultMonths.push(fromMonthNumber(x));
}
return { sales: resultSales, months: resultMonths };
};
With that, interpolateSales([5, 4, 2], ["Jan 2011", "Apr 2011", "Feb 2012"], ["Jan 2011", "Mar 2012"]) is:
{
sales: [5, 5, 4, 4, 4, 4, 3, 3, 3, 3, 3, 2, 2, 2, 2],
months: ["Jan 2011", "Feb 2011", "Mar 2011", "Apr 2011", "May 2011", "Jun 2011", "Jul 2011", "Aug 2011", "Sep 2011", "Oct 2011", "Nov 2011", "Dec 2011", "Jan 2012", "Feb 2012", "Mar 2012"]
}
monthsarray that it had the same value for sales as the previous month?monthsarray? If so (or if it's possible to use Dates), then you should be able to iterate through the months array, keep track of the index, and increment the date by 1 month until you reach the value at the next index, and populate the "result" sales array with the "input" sales value at the previous index. See stackoverflow.com/questions/5645058/… for adding months to dates in javascript