2017-02-26 68 views
1

我有2個日期範圍數組我試圖找出區別。 讓我們用數字,例如:如何區分日期範圍的2個數組之間的區別?

我有2米範圍[1-7, 9-16],我想減去[2-3, 7-9, 14-20] 並獲得[1-1, 4-6, 10-13]

結果的範圍,我陷入一個有點車轍試圖弄清楚的。當然有一個我不知道的通用解決方案?

diffDateRangesArray(rangesArray1, rangesArray2) { 
    //rangesArray = [{startDate, endDate}] 
    let diffedRanges = []; 
    rangesArray1.forEach(function(range1){ 
     //loop through rangesArray2 removing from range1 
     rangesArray2.forEach(function(range2){ 
     // breaks if array returned 
     // perhaps should always return array and flatten? 
     range1 = diffDateRanges(range1, range2); 
     }); 
     diffedRanges.push(range1); 
    }); 
    //probably should do some sort of union here 
    return diffedRanges; 
    } 

    diffDateRanges(range1, range2) { 
    //range = {startDate, endDate} 
    let diffedRange = {}; 
    // if not in range 
    if(range2.endDate <= range1.startDate || range2.startDate >= range1.endDate){ 
     return range1; 
    //if envelops range 
    } else if(range2.endDate >= range1.endDate && range2.startDate <= range1.startDate){ 
     return null; 
    //if cuts off end of range 
    } else if(range2.startDate <= range1.endDate && range2.endDate >= range1.endDate){ 
     return {startDate:range1.startDate, endDate: range2.startDate}; 
    // if cuts off start of range 
    } else if(range2.endDate >= range1.startDate && range2.startDate <= range1.startDate){ 
     return {startDate:range2.endDate, endDate: range1.endDate}; 
    // if inside of range - should better handle arrays 
    } else if(range2.startDate >= range1.startDate && range2.endDate <= range1.endDate){ 
     return [ 
     {startDate:range1.startDate, endDate: range2.startDate}, 
     {startDate:range2.endDate, endDate: range1.endDate}, 
     ]; 
    } 
    } 
+0

我沒有得到如何減去'[2-3,7-9,14-20]''從[1-7 ,9-16]'會導致'[1-1,4-6,10-13]'......你能否更詳細地解釋這一部分,什麼是從什麼等中減去的? –

+0

怎麼樣:我有數字'[1,2,3,4,5,6,7,9,10,11,12,13,14,15,16]',我想刪除'[2 ,3,7,8,9,14,15,16,17,18,19,20]',導致'[1,4,5,6,10,11,12,13]' - 但是輸入並且輸出需要是帶有「{start,end}」的對象而不是一系列。這可能給了我一個想法... –

+0

我想我只需要將'{start,end}'對象轉換成一個數組,並區分它們!然後將它翻譯回一個'{start,end}'陣列 –

回答

1

如果我理解你的問題正確,你可以完成你想要有以下內容:

讓我們先提出一些實用功能:

function range(start, end) { 
    return [...Array(end - start + 1)].map((_, i) => start + i) 
} 

function unique(a) { 
    return Array.from(new Set(a)) 
} 

function immutableSort(arr) { 
    return arr.concat().sort((a, b) => a - b) 
} 

Array.prototype.has = function(e) { 
    return this.indexOf(e) >= 0 
} 

Object.prototype.isEmpty = function() { 
    return Object.keys(this).length === 0 && this.constructor === Object 
} 

function arrayDifference(A, B) { 
    return A.filter((e) => B.indexOf(e) < 0) 
} 

現在,讓我們做一些功能解決您的特定問題:

function arrayToRangeObjects(A) { 
    const preparedA = immutableSort(unique(A)) 
    const minA = preparedA[0] 
    const maxA = preparedA[preparedA.length - 1] 

    const result = [] 
    let rangeObject = {} 
    range(minA, maxA).forEach((v) => { 
    if (!preparedA.has(v)) { 
     if (rangeObject.hasOwnProperty('start')) { 
      if (!rangeObject.hasOwnProperty('end')) { 
      rangeObject.end = rangeObject.start 
      } 
     result.push(rangeObject) 
     } 
     rangeObject = {} 
    } else { 
     if (rangeObject.hasOwnProperty('start')) { 
     rangeObject.end = v 
     } else { 
     rangeObject.start = v 
     } 
    } 
    }) 
    if (!rangeObject.isEmpty()) { 
    result.push(rangeObject) 
    } 
    return result 
} 

function rangeObjectToRange(rangeObject) { 
    return range(rangeObject.start, rangeObject.end) 
} 

function rangeObjectsToRange(A) { 
    return immutableSort(
    unique(
     A 
     .map((rangeObject) => { 
     return rangeObjectToRange(rangeObject) 
     }) 
     .reduce((a, b) => { 
     return a.concat(b) 
     }, []) 
    ) 
) 
} 

因此,您的問題的答案是:

function yourAnswer(A, B) { 
    return arrayToRangeObjects(
    arrayDifference(rangeObjectsToRange(A), rangeObjectsToRange(B)) 
) 
} 

測試一下:

const A = [ 
    { 
    start: 1, 
    end: 7 
    }, 
    { 
    start: 9, 
    end: 16 
    } 
] 

const B = [ 
    { 
    start: 2, 
    end: 3 
    }, 
    { 
    start: 7, 
    end: 9 
    }, 
    { 
    start: 14, 
    end: 20 
    } 
] 

> yourAnswer(A, B) 
[ 
    { 
    start: 1, 
    end: 1 
    }, 
    { 
    start: 4, 
    end: 6 
    }, 
    { 
    start: 10, 
    end: 13 
    } 
] 

正如個人的看法,我認爲這個「範圍的對象」你的數據結構是有點難度的工作吧,又有點不靈活(這一切麻煩只是爲了得到與範圍集合不重疊的範圍):你可能想看看more efficient data structures for storing ranges

+0

非常感謝Marcus! –

+0

你會不會有一個關於如何用r-tree來做到這一點的例子? –

+1

@RyanKing我認爲你的答案中引用的這個['xspans'](https://github.com/exjs/xspans)庫可以做你想做的事,如果你正在考慮間隔。非常好的API:'sub','和','toObjects' ...我喜歡它。 –