Как бы вы использовали коллекторы для группировки по нескольким полям на 2-м уровне. Например:
"someList": {
"firstLevelElementX": {
"secondLevelElementW": 2,
"secondLevelElementZ": 3,
"secondLevelElementK": 7
},
"firstLevelElementY": {
"secondLevelElementW": 1,
"secondLevelElementZ": 3,
"secondLevelElementK": 10
}
}
Я попытался создать класс с элементами "secondLevel" и сгруппировать по этому классу, но не смог заставить его работать:
@Data
@AllArgsConstructor
public class someClass{
private String firstLevelElement;
private Long secondLevelElementW;
private Long secondLevelElementZ;
private Long secondLevelElementK= 0L;
}
И вот как я это делаю:
Map<String,Map<String,Long>> someList =
events.stream().collect(
Collectors.groupingBy(
someDAO::getFirstLevelElement,
Collectors.groupingBy(
someClass::getSecondLevelFields,
Collectors.counting())
)
);
Есть некоторые решения, которые предлагают группировку на n-уровне (с использованием цепочки), но я предпочитаю сделать ее менее сложной и более чистой, если это возможно.
Я попытаюсь привести лучший пример, чтобы прояснить себя, это список, который у меня есть:
{
"date": "2019-04-08 08:28:01.0",
"source": "maint",
"severity": "HARMLESS",
"site": "USA",
"hostname": "usaHost"
},
{
"date": "2019-04-08 08:28:01.0",
"source": "CPU_Checker",
"severity": "MINOR",
"site": "GERMANY",
"hostname": "germanyHost"
},
{
"date": "2019-04-02 08:28:01.0",
"source": "maint",
"severity": "HARMLESS",
"site": "USA",
"hostname": "anotherUsaHost"
}
Я хочу использовать группировку по «источнику» и «серьезности» на втором уровне, поэтому вывод должен выглядеть так:
"eventList": {
"USA": {
"maint": 2,
"HARMLESS": 2
},
"GERMANY": {
"CPU_checker": 1,
"MINOR": 1
}
}
Да, у меня есть List<someDAO>, и каждый DAO содержит несколько полей (поле1, поле2, поле3). Я хочу, чтобы поле1 было элементом на первом уровне, а под ним на втором уровне я хочу суммировать значения поля2 и поля3. (Пожалуйста, см. пример выше для 'someList')
Вы можете суммировать значения полей второго уровня во втором коллекторе groupingBy
:
Map<String, Map<Long, List<someClass>>> result = elements.stream().collect(
groupingBy(someClass::getFirstLevelElement,
groupingBy(s ->
s.getSecondLevelElementK() + s.getSecondLevelElementW() + s.getSecondLevelElementZ()))
);
Интересно, спасибо, посмотрю. Как я могу просмотреть эту карту, чтобы распечатать результаты?
Вы можете просто System.out.println(result)
посмотреть, что внутри, если вам не нужен конкретный формат.
Спасибо за ваш ответ, но, к сожалению, я не могу его принять, так как он не отвечает на вопрос. Я сделал редактирование, чтобы лучше объяснить себя.
Если вы можете использовать Ява 9 или выше, вы можете использовать Collectors.flatMapping()
для достижения этого:
Map<String, Map<String, Long>> eventList = list.stream()
.collect(Collectors.groupingBy(MyObject::getSite, Collectors.flatMapping(
o -> Stream.of(o.getSource(), o.getSeverity()),
Collectors.groupingBy(Function.identity(), Collectors.counting())
)));
Результат будет таким:
{
USA = {maint=2, HARMLESS=2},
GERMANY = {CPU_Checker=1, MINOR=1}
}
Если вы не можете использовать Ява 9, вы можете реализовать функцию flatMapping()
самостоятельно. Вы можете взглянуть на Collectors.flatMapping Java 9, переписанный в Java 8, который должен помочь вам в этом.
Вы пытаетесь суммировать значения из
secondLevelElementW
,secondLevelElementZ
иsecondLevelElementK
? Что такое методsomeClass::getSecondLevelFields
? Непонятно, что вы пытаетесь сделать, когда говорите «группировать по нескольким полям на 2-м уровне».