时间段合并

最近在一个项目中要实现一个时间段合并的业务,即多个可能重复的时间段,合并成一个时间段(应该是取并集)

这里要感谢某技术交流群里的叫嗯*的小哥,给我提供了解决方案

public class EnhanceDataUtil extends DateUtil {
    /**
     * 日期合并 -Date
     * 多个时间段 是有可能部分重合的 汇聚成一条时间线
     * 比如8:00-9:00、8:30-10:30、10:40-11:10、10:36-11:00
     * 最后输出:8:00-10:30、10:36-11:10
     *
     * @param sourceDateRanges 输入多个时间范围的时间段列表
     * @return 合并压缩成只有开始和结束时间的时间段列表
     */
    public static List<Date[]> amalgamateDate(List<Date[]> sourceDateRanges) {
        // 防止入参被篡改 深拷贝
        sourceDateRanges = JSONUtil.toBean(JSONUtil.toJsonStr(CollUtil.emptyIfNull(sourceDateRanges)), new TypeReference<List<Date[]>>() {
        }, true);
        // 返回值
        List<Date[]> amalgamateList = new ArrayList<>();
        // 数据处理
        sourceDateRanges = sourceDateRanges.stream()
                // 去掉空元素
                .map(ArrayUtil::removeNull)
                // 只保留元素个数大于1的
                .filter(sourceDateRange -> ArrayUtil.length(sourceDateRange) > 1)
                // 只保留start和end
                .map(sourceDateRange -> new Date[]{
                        ArrayUtil.min(sourceDateRange),
                        ArrayUtil.max(sourceDateRange)
                })
                .map(sourceDateRange ->
                        Convert.convert(DateTime[].class, sourceDateRange))
                // 排序
                .sorted((o1, o2) -> CompareUtil.compare(o1[0], o2[0]))
                .collect(Collectors.toList());
        /**
         * 时间段位置映射集 以源列表时间段的索引为key,合并到结果列表的索引为value
         * sourceDateRangesIndex:amalgamateListIndex
         */
        HashMap<Integer, Integer> indexMap = new HashMap<>();
        // 添加首个元素
        if (CollUtil.isNotEmpty(sourceDateRanges)) {
            amalgamateList.add(CollUtil.getFirst(sourceDateRanges));
            indexMap.put(0, 0);
        }
        /**
         * 开始合并:
         * amalgamateList能够确保是没有任何交集的时间段列表
         * sourceDateRanges是按照时间段中的起始时间正序排列的列表,是有可能有交集的
         * 上面的排序很重要,能够确保每次拿到最新的时间段数据 不会合并到amalgamateList前面的元素中,只能合并到最后一个时间段或者开启新的时间段
         */
        for (int index = 1; index < sourceDateRanges.size(); index++) {
            // 找到上一个合并好的时间段
            Date[] amalgamateDateRange = amalgamateList.get(indexMap.get(index - 1));
            // 当前待合并的时间段
            Date[] currentIndexDataRange = sourceDateRanges.get(index);
            if (isIn(currentIndexDataRange[0], amalgamateDateRange[0], amalgamateDateRange[1])) {
                // 如果当前时间段的起始时间在上个合并好的时间段内 调整上个时间段的起始、结束点
                amalgamateDateRange[0] = CollUtil.min(Arrays.asList(amalgamateDateRange[0], currentIndexDataRange[0]));
                amalgamateDateRange[1] = CollUtil.max(Arrays.asList(amalgamateDateRange[1], currentIndexDataRange[1]));
                // 未合并列表索引:合并到amalgamateList的索引
                indexMap.put(index, indexMap.get(index - 1));
            } else {
                amalgamateList.add(currentIndexDataRange);
                // 未合并列表索引:新增到amalgamateList的索引
                indexMap.put(index, CollUtil.size(amalgamateList) - 1);
            }
        }
        return amalgamateList;
    }

    /**
     * 日期合并 - LocalDateTime
     *
     * @param sourceDateRanges
     * @return
     */
    public static List<LocalDateTime[]> amalgamateLocalDateTime(List<LocalDateTime[]> sourceDateRanges) {
        ZoneId zoneId = ZoneId.systemDefault();
        return amalgamateDate(
                sourceDateRanges.stream().map(range ->
                                Arrays.stream(range)
                                        .map(time ->
                                                ObjectUtil.isEmpty(time) ? null : Date.from(time.atZone(zoneId).toInstant()))
                                        .collect(Collectors.toList())
                                        .toArray(new Date[0]))
                        .collect(Collectors.toList())
        ).stream().map(dateRange ->
                        Arrays.stream(dateRange)
                                .map(date ->
                                        date.toInstant().atZone(zoneId).toLocalDateTime())
                                .collect(Collectors.toList())
                                .toArray(new LocalDateTime[0]))
                .collect(Collectors.toList()
                );
    }


}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值