在Java流中按日期汇总数据

时间:2019-07-04 07:47:29

标签: java java-8 java-stream

我有一个StatisticsItemString context, Integer numberOfHits, String yyyyMM)列表。 实例的一个例子是context=WEBSITE, numberOfHits=12456, yyyyMM="2019-06"

我想获得一个排序的Map<String, Integer>,该关键字具有yyyyMM日期和该月的总点击数作为值。

我尝试了这种代码,但我无法填补空白:

Map<String, Integer> collect = 
      list.stream()
          .sorted((s1, s2) -> s1.getYearAndMonth().compareTo(s2.getYearAndMonth()))
          ./* TODO: What method ? */((s1, s2) -> s1.getYearAndMonth().equals(s2.getYearAndMonth())
            ? new StatisticsItem(s1.getNumberOfHits() + s2.getNumberOfHits(), s1.getYearAndMonth()) // Construct new StatistictsItem without "context"
            : /* TODO: don't touch data with different dates */)
    .collect(Collectors.toMap(s -> s.getYearAndMonth(), s -> s.getNumberOfHits()));

输入:

{context="WEBSITE", numberOfHits=500, yyyyMM="2019-04", 
context="WEBSITE", numberOfHits=750, yyyyMM="2019-05", 
context="WEBSITE", numberOfHits=470, yyyyMM="2019-06",
context="REST", numberOfHits=5400, yyyyMM="2019-04", 
context="REST", numberOfHits=4700, yyyyMM="2019-05", 
context="REST", numberOfHits=9700, yyyyMM="2019-06"}

所需的输出(在这种情况下,上下文可以为null或其他任何值):

{context=null, numberOfHits=5900, yyyyMM="2019-04", 
context=null, numberOfHits=5450, yyyyMM="2019-05", 
context=null, numberOfHits=10170, yyyyMM="2019-06"}

2 个答案:

答案 0 :(得分:4)

您可以按日期字段进行分组。

list.stream().groupingBy(StatisticsItem::getYyyyMM, 
              Collectors.mapping(StatisticsItem::getNumberOfHits, Collectors.summingInt(Integer::intValue)))

然后您有一个Map<String, Integer>,其中包含[yyyyMM-count]个条目。

答案 1 :(得分:1)

似乎您确实需要一个汇总的Collection<StatisticsItem>,所以类似:

list.stream()
     .collect(Collectors.toMap(
         StatisticsItem::getYearAndMonth,
         Function.identity(),
         (left, right) -> {
              left.setNumberOfHits(left.getNumberOfHits() + right.getNumberOfHits());
              // map context how you want
              return left;
         }
     )
 )
 .values()

这个想法是,您可以合并上面示例中的leftright,当有两个(或更多)实例具有相同的{{1}时,如何合并它们}