You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java Stream如何调整groupingBy逻辑实现按指定天数日期窗口分组

实现方案

核心改动仅需调整Collectors.groupingBy的分组分类器,将原精确日期匹配改为按时间窗口编号匹配即可,原组内取最大值的逻辑无需修改。

前置说明

默认ObjectA.getDate()返回java.time.LocalDate类型(Java 8+推荐的日期类型),如果是旧版java.util.Date可参考文末的兼容方案。

完整代码实现

// 定义时间窗口天数
int daysWindow = 90;

List<ObjectA> collapsed = list.stream().collect(Collectors.collectingAndThen(
        Collectors.groupingBy(
                // 替换原分组逻辑为时间窗口编号计算
                obj -> {
                    // 计算当前日期与纪元日(1970-01-01)的天数差,除以窗口大小取整得到窗口编号
                    long dayDiff = ChronoUnit.DAYS.between(LocalDate.EPOCH, obj.getDate());
                    return dayDiff / daysWindow;
                },
                Collectors.maxBy(Comparator
                        .comparing(ObjectA::getPriority1)
                        .thenComparing(ObjectA::getPriority2)
                        .thenComparing(ObjectA::getDate)
                        .thenComparing(ObjectA::getId))),
        map -> map.values().stream()
                .filter(Optional::isPresent)
                .map(Optional::get)
                .collect(Collectors.toList())));

旧版java.util.Date兼容方案

如果ObjectA.getDate()返回的是java.util.Date,修改分组分类器的逻辑如下即可:

obj -> {
    // 注意时区可根据业务需要替换为指定时区,比如ZoneId.of("Asia/Shanghai")
    LocalDate localDate = obj.getDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
    long dayDiff = ChronoUnit.DAYS.between(LocalDate.EPOCH, localDate);
    return dayDiff / daysWindow;
}

逻辑说明

  • 时间窗口编号计算逻辑:以1970-01-01为基准,每daysWindow天划分为一个窗口,同一天窗口内的所有日期计算得到的编号完全一致,因此会被分到同一组
  • 如果业务要求以集合内最早的日期为窗口起始基准,可以先提前计算集合的最小日期替换上述代码中的LocalDate.EPOCH即可

内容的提问来源于stack exchange,提问作者Ed-Genesis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 18:27:02