【问题标题】:Collectors nested grouping-by with multiple fields收集器嵌套分组,具有多个字段
【发布时间】:2019-08-31 16:11:00
【问题描述】:

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

"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
        }
}

【问题讨论】:

  • 您是否要对来自secondLevelElementWsecondLevelElementZsecondLevelElementK 的值求和?什么是someClass::getSecondLevelFields 方法?当您说“在 2 级按多个字段分组”时,不清楚您要做什么。
  • 是的,我有一个List,每个DAO包含几个字段(field1,field2,field3)。我希望 field1 成为第一级的元素,并在第二级下,我想总结 field2 和 field3 的值。 (请参见上面的“someList”示例)

标签: java spring java-stream collectors


【解决方案1】:

您可以在第二个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) 即可查看里面的内容。
  • 感谢您的回复,但很遗憾我无法接受,因为它没有回答问题。为了更好地解释我自己,我进行了编辑。
【解决方案2】:

如果您可以使用 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,它应该可以帮助你。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-11-26
    • 2017-09-26
    • 1970-01-01
    • 2011-08-07
    • 2021-01-09
    • 2019-09-03
    • 2017-09-15
    相关资源
    最近更新 更多