如何获得 2 个日期范围数组之间的差异?
How to get the difference between 2 Arrays of Date Ranges?
我有 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},
];
}
}
如果我理解你的问题是正确的,你可以通过以下方式完成你想要的:
让我们先做一些实用函数:
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
}
]
就个人意见而言,我认为你的这个 "range object" 数据结构有点难以处理,而且有点不灵活(所有这些麻烦只是为了获得不与范围集合):你可能想看看 more efficient data structures for storing ranges.
原来这叫做区间代数,并且有相关的库
https://www.npmjs.com/package/qintervals
我有 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},
];
}
}
如果我理解你的问题是正确的,你可以通过以下方式完成你想要的:
让我们先做一些实用函数:
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
}
]
就个人意见而言,我认为你的这个 "range object" 数据结构有点难以处理,而且有点不灵活(所有这些麻烦只是为了获得不与范围集合):你可能想看看 more efficient data structures for storing ranges.
原来这叫做区间代数,并且有相关的库 https://www.npmjs.com/package/qintervals