[英]Merge overlapping date ranges
如何在数组上合并重叠的日期范围?
我有一系列日期:
const dates = [
{startDate: "2020-03-19T00:00:00+01:00", endDate: "2020-03-20T00:00:00+01:00"},
{startDate: "2020-03-09T00:00:00+01:00", endDate: "2020-03-16T00:00:00+01:00"},
{startDate: "2020-02-07T00:00:00+01:00", endDate: "2020-03-09T00:00:00+01:00"},
{startDate: "2020-02-07T00:00:00+01:00", endDate: "2020-02-13T00:00:00+01:00"}
];
我想要完成的是合并重叠数组,这样我就会得到结果:
//Result I'm looking for:
const mergedDates = [
{startDate: "2020-03-19T00:00:00+01:00", endDate: "2020-03-20T00:00:00+01:00"},
{startDate: "2020-02-07T00:00:00+01:00", endDate: "2020-03-16T00:00:00+01:00"}
];
我正在使用moment-range
创建范围:
const ranges = dates.map(d => {
return moment.range(d.startDate, d.endDate);
});
然后我使用两个for
循环来找出重叠
let arrRange = [];
for (let i = 0; i < ranges.length; i++) {
const el1 = ranges[i];
let loop=[];
for (let i = 0; i < ranges.length; i++) {
const el2 = ranges[i];
const overlaps = el1.overlaps(el2, { adjacent: true });
if(overlaps){
loop = [...loop, i]
}
}
arrRange.push(loop);
}
}
这给了我一个数组,其中有索引数组,所以我知道重叠在哪里:
console.log(arrRange);
// [[0], [1, 2], [1, 2, 3], [2, 3]]
但是,我被困住了。
即使知道重叠,我也无法弄清楚如何合并它们。
我会使用Math.min
和Math.max
来获取每个重叠范围的第一个和最后一个日期端点,然后将每个索引数组减少到合并的范围对象:
const merged = arrRange.map(idxArray => {
const { min, max } = idxArray.reduce(({ min, max }, index) => {
const range = ranges[index];
return {
min: Math.min(min, range.start.toDate()),
max: Math.max(max, range.end.toDate())
};
}, { min: Number.MAX_VALUE, max: Number.MIN_VALUE }); // throwaway value
return moment.range(new Date(min), new Date(max));
});
var rawArray = [
{ name: 'C', startDate: '2021/02/01', endDate: '2021/02/15' },
{ name: 'A', startDate: '2021/01/01', endDate: '2021/01/15' },
{ name: 'D', startDate: '2021/02/12', endDate: '2021/02/25' },
{ name: 'E', startDate: '2021/02/22', endDate: '2021/02/28' },
{ name: 'F', startDate: '2021/03/01', endDate: '2021/03/15' },
{ name: 'B', startDate: '2021/01/12', endDate: '2021/01/30' },
]
console.log('Input', rawArray)
for (var i = 0; i < rawArray.length; i++) {
for (var j = i + 1; j < rawArray.length; j++) {
if (isBetweenOrOverlap(rawArray[i].startDate, rawArray[i].endDate, rawArray[j].startDate, rawArray[j].endDate)) {
rawArray[i].startDate = getLeastDate(rawArray[i].startDate, rawArray[j].startDate);
rawArray[i].endDate = getMaxDate(rawArray[i].endDate, rawArray[j].endDate);
rawArray.splice(j, 1);
i = i - 1;
break;
}
}
}
console.log('Ouput', rawArray)
Input [
{ name: 'C', startDate: '2021/02/01', endDate: '2021/02/15' },
{ name: 'A', startDate: '2021/01/01', endDate: '2021/01/15' },
{ name: 'D', startDate: '2021/02/12', endDate: '2021/02/25' },
{ name: 'E', startDate: '2021/02/22', endDate: '2021/02/28' },
{ name: 'F', startDate: '2021/03/01', endDate: '2021/03/15' },
{ name: 'B', startDate: '2021/01/12', endDate: '2021/01/30' }
]
Ouput [
{ name: 'C', startDate: '2021/02/01', endDate: '2021/02/28' },
{ name: 'A', startDate: '2021/01/01', endDate: '2021/01/30' },
{ name: 'F', startDate: '2021/03/01', endDate: '2021/03/15' }
]
我今天必须这样做(打字稿,但你明白了):
interface DateRange {
start: Date;
end: Date;
}
export function mergeOverlappingDateRanges(
dateRanges: DateRange[],
): DateRange[] {
const sorted = dateRanges.sort(
// By start, ascending
(a, b) => a.start.getTime() - b.start.getTime(),
);
const ret = sorted.reduce((acc, curr) => {
// Skip the first range
if (acc.length === 0) {
return [curr];
}
const prev = acc.pop();
if (curr.end <= prev.end) {
// Current range is completely inside previous
return [...acc, prev];
}
// Merges overlapping (<) and contiguous (==) ranges
if (curr.start <= prev.end) {
// Current range overlaps previous
return [...acc, { start: prev.start, end: curr.end }];
}
// Ranges do not overlap
return [...acc, prev, curr];
}, [] as DateRange[]);
return ret;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.