收集器嵌套分组依据与多个字段
Collectors nested grouping-by with multiple fields
您将如何使用收集器在第 2 级按多个字段进行分组。例如:
"someList": {
"firstLevelElementX": {
"secondLevelElementW": 2,
"secondLevelElementZ": 3,
"secondLevelElementK": 7
},
"firstLevelElementY": {
"secondLevelElementW": 1,
"secondLevelElementZ": 3,
"secondLevelElementK": 10
}
}
我试图用 "secondLevel" 个元素创建一个 class,并按此 class 进行分组,但无法成功:
@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"
}
我想在第二层 'source' 和 'severity' 上使用 group-by,因此输出应该如下所示:
"eventList": {
"USA": {
"maint": 2,
"HARMLESS": 2
},
"GERMANY": {
"CPU_checker": 1,
"MINOR": 1
}
}
您可以在第二个 groupingBy
收集器中汇总二级字段值:
Map<String, Map<Long, List<someClass>>> result = elements.stream().collect(
groupingBy(someClass::getFirstLevelElement,
groupingBy(s ->
s.getSecondLevelElementK() + s.getSecondLevelElementW() + s.getSecondLevelElementZ()))
);
如果您可以使用 Java 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}
}
如果你不会使用Java9你可以自己实现flatMapping()
功能。你可以看看 ,这应该对你有帮助。
您将如何使用收集器在第 2 级按多个字段进行分组。例如:
"someList": {
"firstLevelElementX": {
"secondLevelElementW": 2,
"secondLevelElementZ": 3,
"secondLevelElementK": 7
},
"firstLevelElementY": {
"secondLevelElementW": 1,
"secondLevelElementZ": 3,
"secondLevelElementK": 10
}
}
我试图用 "secondLevel" 个元素创建一个 class,并按此 class 进行分组,但无法成功:
@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"
}
我想在第二层 'source' 和 'severity' 上使用 group-by,因此输出应该如下所示:
"eventList": {
"USA": {
"maint": 2,
"HARMLESS": 2
},
"GERMANY": {
"CPU_checker": 1,
"MINOR": 1
}
}
您可以在第二个 groupingBy
收集器中汇总二级字段值:
Map<String, Map<Long, List<someClass>>> result = elements.stream().collect(
groupingBy(someClass::getFirstLevelElement,
groupingBy(s ->
s.getSecondLevelElementK() + s.getSecondLevelElementW() + s.getSecondLevelElementZ()))
);
如果您可以使用 Java 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}
}
如果你不会使用Java9你可以自己实现flatMapping()
功能。你可以看看