【问题标题】:Group by packets of n hours按 n 小时的数据包分组
【发布时间】:2018-10-07 23:18:47
【问题描述】:

我有一个带有 LocalDateTime 字段 (controlDate) 和一个 int (orders) 字段以及其他字段的 Java POJO,但与我的问题无关。

我正在从我的数据库中获取此 POJO 的列表,例如:

controlDate                 orders
2018-10-07 23:26:00.000+02  5
2018-10-07 23:27:00.000+02  2
2018-10-07 18:33:00.000+02  8
2018-10-07 18:35:00.000+02  4

我的最终目标是按 n 小时的数据包聚合数据(并将最旧的日期保留为聚合日期),并通过获取“订单”列的平均值

例如值 n = 2,我想得到类似的东西:

controlDate                 orders
2018-10-07 23:26:00.000+02  3 (or 4, I don't really care about the rounding)
2018-10-07 18:33:00.000+02  6

我很确定使用 Java 8 流我可以实现这一点,可能使用 Collectors.groupingBy,但我不知道我究竟如何实现这一点......

感谢您的帮助!

【问题讨论】:

  • SQL 有一些非常强大的分组功能(参见GROUP BYHAVING)。这可能更合适,并为您节省一些 Java 编码。
  • 嗨,戴夫,事实上,我的第一个方法是在 SQL 中执行此操作,并且我使用 Hibernate 本机查询成功获得了 MySQL SGBD。现在我必须迁移到 PostgreSQL,所以我必须编写一个全新的本机查询。我意识到这不是最好的方法(如果明天我要迁移到 Oracle 或其他 SGBD 怎么办?)这就是为什么我试图将聚合部分委托给我的 Java 代码以独立于 SGBD。我试图查看 Hibernate 文档,但我没有找到任何可以实现我想要做的事情,除了原生查询
  • 很公平。在这种情况下,按照 SO 方式,您可能应该向我们展示您目前拥有的代码。
  • 这些时间戳与 UTC 有一个偏移量,这意味着它们代表一个时刻,即时间线上的一个特定点。在这种情况下,LocalDateTime 是错误的类,因为该类不能代表片刻。请改用OffsetDateTime
  • 据我所见,在您的示例结果中,流不会很适合第一次在组中分组。如果按整小时分组是可以的(如到目前为止发布的第一个答案),流可能没问题。

标签: java date java-8 grouping


【解决方案1】:

这段代码应该可以解决问题:

class Delivery {
    LocalDateTime timestamp;
    Integer packages;

    public Delivery(LocalDateTime timestamp, Integer packages) {
        this.timestamp = timestamp;
        this.packages = packages;
    }


    public Integer getPackages() {
        return packages;
    }

    public LocalDate getDate() {
        return timestamp.toLocalDate();
    }

    public Integer getHour() {
        return timestamp.getHour();
    }

}

public class Calculate {

    public static void main(final String[] args) {
        Stream<Delivery> deliveries = Stream.of(
                new Delivery(LocalDateTime.of(2018, 10, 7, 23, 26), 5),
                new Delivery(LocalDateTime.of(2018, 10, 7, 23, 27), 2),
                new Delivery(LocalDateTime.of(2018, 10, 7, 18, 33), 8),
                new Delivery(LocalDateTime.of(2018, 10, 7, 18, 35), 4)
        );

        deliveries.map(delivery -> {
            Map r = new HashMap();
            r.put(delivery.getHour(), delivery.getPackages());
            return r;
        }).collect(Collectors.groupingBy(d -> d.keySet().toArray()[0])).forEach((o, packages) -> {
            System.out.print(o + ":");
            Integer sum = (Integer) packages.stream().map(map -> map.get(o)).reduce(0, (a, b) -> (Integer) a + (Integer) b);
            long count = packages.stream().count();
            System.out.println(sum / count);
        });
    }
}

你会得到:

18:6
23:3

它按小时排序,因此您可以扩展此解决方案以满足您的需求。

【讨论】:

  • 对于足够大的数据库结果,这可能会引发 OOM
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-08
相关资源
最近更新 更多