How would you use Collectors in order to group by multiple fields at 2nd level. for example:
"someList": {
"firstLevelElementX": {
"secondLevelElementW": 2,
"secondLevelElementZ": 3,
"secondLevelElementK": 7
},
"firstLevelElementY": {
"secondLevelElementW": 1,
"secondLevelElementZ": 3,
"secondLevelElementK": 10
}
}
I tried to create a class with "secondLevel" elements, and group-by this class, but couldn't make it work:
@Data
@AllArgsConstructor
public class someClass{
private String firstLevelElement;
private Long secondLevelElementW;
private Long secondLevelElementZ;
private Long secondLevelElementK= 0L;
}
And this is how I do it :
Map<String,Map<String,Long>> someList =
events.stream().collect(
Collectors.groupingBy(
someDAO::getFirstLevelElement,
Collectors.groupingBy(
someClass::getSecondLevelFields,
Collectors.counting())
)
);
There are some solutions which suggest n-level grouping (using chain), but I prefer to make it less complicated and more clean if possible.
I will try to provide a better example in order to clarify myself, this is the list that I have :
{
"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"
}
I want to use group-by on 'source' and 'severity' at the second level, so the output should look like this :
"eventList": {
"USA": {
"maint": 2,
"HARMLESS": 2
},
"GERMANY": {
"CPU_checker": 1,
"MINOR": 1
}
}
If you can use Java 9 or higher, you can use Collectors.flatMapping()
to achieve that:
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())
)));
The result will be this:
{
USA={maint=2, HARMLESS=2},
GERMANY={CPU_Checker=1, MINOR=1}
}
If you are not able to use Java 9 you can implement the flatMapping()
function yourself. You can take a look at Java 9 Collectors.flatMapping rewritten in Java 8, which should help you with that.