Агрегировать данные по дате в потоке Java - PullRequest
4 голосов
/ 04 июля 2019

У меня есть список StatisticsItem (String 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"}

Желаемый вывод (контекст может быть нулевым или любым другим в этом случае):

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

Ответы [ 2 ]

4 голосов
/ 04 июля 2019

Вы можете просто группировать по полю даты.

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

Тогда у вас есть Map<String, Integer> с [yyyyMM - count] записей.

1 голос
/ 04 июля 2019

Кажется, вам действительно нужно агрегировать 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()

Идея состоит в том, что вы можете объединить (left и right) в приведенном выше примере какВы хотите, чтобы они были объединены, когда два (или более) экземпляра имеют одинаковый yearAndMonth

...