收集器使用多个字段嵌套分组

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了收集器使用多个字段嵌套分组相关的知识,希望对你有一定的参考价值。

如何使用收集器以便在第二级按多个字段进行分组。例如:

"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级分组(使用链),但如果可能的话,我更喜欢使它更简单,更干净。

Edit

我将尝试提供一个更好的例子来澄清自己,这是我的清单:

{
      "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
        }
}
答案

如果您可以使用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}
}

如果您无法使用Java 9,您可以自己实现flatMapping()功能。你可以看看Java 9 Collectors.flatMapping rewritten in Java 8,它可以帮助你。

另一答案

您可以在第二个groupingBy收集器中总结第二级字段值:

Map<String, Map<Long, List<someClass>>> result = elements.stream().collect(
        groupingBy(someClass::getFirstLevelElement,
            groupingBy(s -> 
                s.getSecondLevelElementK() + s.getSecondLevelElementW() + s.getSecondLevelElementZ()))
);

以上是关于收集器使用多个字段嵌套分组的主要内容,如果未能解决你的问题,请参考以下文章

5.sql2008分组与嵌套

访问嵌套片段的文本字段

使用 XSLT 基于父字段的嵌套分组

MongoDB聚合和分组嵌套字段

CSS进阶篇——分组和嵌套

CSS进阶篇——分组和嵌套