2013-03-07 49 views
1

說我有以下幾點:如何在JavaScript數組中插入缺失的日期和數據點?

var sales = [5, 4, 2]; 
var months = ["Jan 2011", "Apr 2011", "Feb 2012"]; 

如果我有一個給定的範圍說:

var range = ["Jan 2011", "Mar 2012"]; 

我想個月之間,以「插值」,這樣我可以得到的結果是:

var sales = [5, 4, 4, 4, ..., 2, 2]; 
var months = ["Jan 2011", "Feb 2011", "Mar 2011", ...., "Feb 2012", "Mar 2012"]; 

是否有必要根據需要包含的所有「月份+年份」創建「連續排列的所有可能日期的範圍」數組?或者是否有可能與JavaScript不必這樣做? 如何做到這一點?

注意:假設是,如果日期不存在於months數組中,則它將填入來自任何以前可用月份的數據。

+0

是A假設如果一個日期不存在於'months'數組中,它與前一個月的銷售價值相同? – atkretsch 2013-03-07 22:44:30

+0

是的,假設是如果日期不存在於月份數組中,它將填入任何以前可用月份的數據。 – Rolando 2013-03-08 06:25:55

+0

你在'months'數組中使用實際的Date對象嗎?如果是這樣(或者可以使用日期),那麼您應該能夠遍歷月份數組,跟蹤索引,並將日期遞增1個月,直到達到下一個索引的值,然後填充「結果」銷售數組與前一指數的「輸入」銷售價值。請參閱http://stackoverflow.com/questions/5645058/how-to-add-months-to-a-date-in-javascript在javascript中添加月份到日期 – atkretsch 2013-03-08 16:59:07

回答

2

如果不嚴格需要使用以前已知的銷售數字,則可以使用一個不錯的一種樣條插值的銷售數字:

/* 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; 
    }; 
}; 

,可以用下面的代碼可以用來做你想要的東西:

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 }; 
}; 

就這樣,interpolateSales([5, 4, 2], ["Jan 2011", "Apr 2011", "Feb 2012"], ["Jan 2011", "Mar 2012"])是:

{ 
    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"] 
}