2017-02-26 30 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' ...我喜欢它。 –