【问题标题】:Java - Collectors.groupingBy - the last 15 daysJava - Collectors.groupingBy - 过去 15 天
【发布时间】:2021-12-28 21:01:21
【问题描述】:

是否可以使用 Java 的 Collectors.groupingBy 按过去 15 天分组?

输入:

public class Tweet { 

 String id;
 LocalDate createdAt; 

 // Constructor Ignored

 List<Tweet> tweets = new ArrayList(){{
  add(new Tweet("1", "2021-11-17"));
  add(new Tweet("2", "2021-11-16"));
  add(new Tweet("3", "2021-11-14"));
  add(new Tweet("4", "2021-11-13"));
  add(new Tweet("5", "2021-11-12"));
  add(new Tweet("7", "2021-10-09"));
  add(new Tweet("8", "2021-10-08"));
  add(new Tweet("9", "2021-10-07"));
  add(new Tweet("10", "2021-09-02"));
  add(new Tweet("11", "2021-09-01"));
 ...

 }};

}

预期输出:

2021-11-17:  (group must include 2021-11-17 + 15 days before 17th)
 Tweet("1", "2021-11-17");
 Tweet("2", "2021-11-16");
 Tweet("3", "2021-11-14");
 Tweet("4", "2021-11-13");
 Tweet("5", "2021-11-12");

2021-10-09: (group to include 2021-10-09 + 15 days before 9th)
 Tweet("7", "2021-10-09");
 Tweet("8", "2021-10-08");
 Tweet("9", "2021-10-07");

2021-09-01: (group to include 2021-09-01 + 15 days before 1st)
Tweet("10", "2021-09-02");
Tweet("11", "2021-09-01");

当前逻辑(不起作用):

主要方法:


TemporalAdjusters adjuster = TemporalAdjusters.ofDateAdjuster(d -> d.minusDays(15));

Map<LocalDate, List<Tweets>> groupByLast15Days = tweets.stream()
                .collect(Collectors.groupingBy(item -> item.createdAt())
                  .with(adjuster)));

System.out.println(groupByLast15Days);  // provides incorrect results

非常感谢任何帮助!谢谢!

【问题讨论】:

  • 为什么不改用.filter(...)
  • @blurfus - 我不认为只有filter() 可以做到这一点。 Collectors.GroupBy 看起来更优雅。
  • 您是否要分组到长度为 15 天的存储桶中?或者过滤掉超过 15 天前的条目?
  • @LouisWasserman - 我正在尝试将它们分组为 15 天长度的存储桶。

标签: java collectors


【解决方案1】:

您可以使用ChronoUnit.DAYS.between(from,to) 获取两个LocalDateTimes 之间的日差,如here 所述。

然后您可以将其除以 15(因此您在该范围内的所有天数都相同):

LocalDate origin=LocalDate.now();
Map<LocalDate, List<Tweets>> groupByLast15Days = tweets.stream()
    .collect(Collectors.groupingBy(item-> 
       Long.valueOf(ChronoUnit.DAYS.between(item.createdAt(),origin)/15));

如果你想按开始日期分组,你可以颠倒计算(而15天之间的差异被整数除法消除):

LocalDate origin=LocalDate.now();
Map<LocalDate, List<Tweets>> groupByLast15Days = tweets.stream()
    .collect(Collectors.groupingBy(item -> 
        origin.plusDays(
            (ChronoUnit.DAYS.between(origin, item.createdAt()) /15)*15
        )
    ));

如果你想使用TemporalAdjusters,你可以这样做:

LocalDate origin=LocalDate.now();
TemporalAdjusters adjuster = TemporalAdjusters.ofDateAdjuster(d ->
    origin.plusDays(
        (ChronoUnit.DAYS.between(origin, d) /15)*15
    )
);

说明

一个整数除以另一个整数总是得到一个整数,即使商会有小数位。整数除法只是删除那些小数位。如果将一个数字除以 15,它将返回 15 个连续数字的相同结果。再次乘以 15 后,您将得到这 15 个数字中的第一个。将一个数字除以 15 并再次乘以 15 的目的是将每 15 个连续数字设置为相同的数字(这 15 个数字中的第一个)。

ChronoUnit.DAYS.between(date1, date2) 只是计算date1date2 之间的天数。

【讨论】:

  • 哇,真快.. 是否可以将原点设为item.createdAt() 而不是now()?我想按item.createAt() - 15 对它们进行分组。 creationAt 日期可能不是今天的日期..
  • origin 可以是任何日期,但所有元素的日期必须相同。
  • 唯一的区别是每组 15 天的开始时间(将origin 移动一天意味着每个块将在一天后开始,将其移动 15 天没有任何作用)
  • 我修好了。查看我的编辑。
  • 我编辑了我的答案。是的,将两者都更改为 10 将每连续 10 天合并一次。
猜你喜欢
  • 1970-01-01
  • 2020-10-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-28
  • 2012-11-09
相关资源
最近更新 更多