首页 > 解决方案 > Java合并重叠日期间隔

问题描述

通常这种类型的算法是使用 SQL(间隙和孤岛)完成的,但我需要找到一种在 Java 中完成的方法。

我有一组对象:Set<UnavailableBlock>

UnavailableBlock如下(简化):

@Getter
@Setter
@AllArgsConstructor
@ToString
public class UnavailableBlock{
    OffsetDateTime blockStartTime;
    OffsetDateTime blockEndTime;
}

允许重叠间隔,所以我试图返回一个Set<UnavailableBlock>但合并的间隔,在它们之间留下各自的间隙。我正在使用 OffsetDateTime 并且需要考虑时间。

例如(使用 Outlook):

[1]:https://i.stack.imgur.com/zK8h0.png

private Set<AppointmentAvailabilityBlock> mergeUnavailabilitiesBlocks(
    Set<AppointmentAvailabilityBlock> appointmentComponentUnavailabilitiesBlock) {

// Transform Set to List
List<AppointmentAvailabilityBlock> intervals = new LinkedList<AppointmentAvailabilityBlock>();
intervals.addAll(appointmentComponentUnavailabilitiesBlock);

// Sort by blockStartTime
intervals.sort(Comparator.comparing(AppointmentAvailabilityBlock::getBlockStartTime));

// Merge
LinkedList<AppointmentAvailabilityBlock> merged = new LinkedList<>();
for (AppointmentAvailabilityBlock interval : intervals) {
    // No overlap with the previous interval, append it.
    if (merged.isEmpty() || merged.getLast().getBlockEndTime().isBefore(interval.getBlockStartTime())) {
        merged.add(interval);
    } else { // There is overlap
        OffsetDateTime maxOffsetDateTime = merged.getLast().getBlockEndTime().isAfter(
                interval.getBlockEndTime()) ? merged.getLast().getBlockEndTime() : interval.getBlockEndTime();
        
        merged.getLast().setBlockEndTime(maxOffsetDateTime);
    }
}
return new HashSet<AppointmentAvailabilityBlock>(merged);
}

问题是我不断得到重叠的块:

橙色 = 合并前

绿色 = 合并后

在此处输入图像描述

注意:我正在使用带有 lombok 注释的 Spring Boot

标签: javadatetimemergeoverlapgaps-and-islands

解决方案


private Set<AppointmentAvailabilityBlock> mergeUnavailabilitiesBlocks(
    Set<AppointmentAvailabilityBlock> appointmentComponentUnavailabilitiesBlock) {

// Transform Set to List
List<AppointmentAvailabilityBlock> intervals = new LinkedList<AppointmentAvailabilityBlock>();
intervals.addAll(appointmentComponentUnavailabilitiesBlock);

// Sort by blockStartTime
intervals.sort(Comparator.comparing(AppointmentAvailabilityBlock::getBlockStartTime));

// Merge
LinkedList<AppointmentAvailabilityBlock> merged = new LinkedList<>();
for (AppointmentAvailabilityBlock interval : intervals) {
    // No overlap with the previous interval, append it.
    if (merged.isEmpty() || merged.getLast().getBlockEndTime().isBefore(interval.getBlockStartTime())) {
        merged.add(interval);
    } else { // There is overlap
        OffsetDateTime maxOffsetDateTime = merged.getLast().getBlockEndTime().isAfter(
                interval.getBlockEndTime()) ? merged.getLast().getBlockEndTime() : interval.getBlockEndTime();
        
        merged.getLast().setBlockEndTime(maxOffsetDateTime);
    }
}
return new HashSet<AppointmentAvailabilityBlock>(merged);
}

推荐阅读