【问题标题】:How to aggregate grouped entities after stream groupingBy流分组后如何聚合分组实体
【发布时间】:2021-10-22 18:56:18
【问题描述】:

我有一个简单的课程Person:

class Person {
    String firstName;
    String lastName;
    //getter, setter, constructor, toString
}

还有一个Persons 的输入列表,比如:

List<Person> myList = List.of(
        new Person("Helena", "Graves"),
        new Person("Jasmine", "Knight"),
        new Person("Phoebe", "Reyes"),
        new Person("Aysha", "Graham"),
        new Person("Madeleine", "Jenkins"),
        new Person("Christina", "Johnson"),
        new Person("Melissa", "Carpenter"),
        new Person("Marie", "Daniel"),
        new Person("Robin", "French"),
        new Person("Tamara", "Wyatt"),
        new Person("Freya", "Montgomery"),
        new Person("Lacey", "Todd"),
        new Person("Heather", "Parker"),
        new Person("Lauren", "Wright"),
        new Person("Annie", "Bradley")
);

现在我需要按人的姓氏的第一个字符对上面的列表进行分组,然后再次对这些组进行分组,以便所有以A-H 开头的姓氏都属于一个组,以@987654326 开头的姓氏属于下一组@ 最后是O-Z

我已经可以按姓氏的第一个字符对列表进行分组:

myList.stream()
        .collect(Collectors.groupingBy(p -> String.valueOf(p.getLastName().charAt(0))))
        .entrySet()
        .forEach(System.out::println);

这给了我:

P=[Person{Heather, Parker}]
B=[Person{Annie, Bradley}]
R=[Person{Phoebe, Reyes}]
C=[Person{Melissa, Carpenter}]
T=[Person{Lacey, Todd}]
D=[Person{Marie, Daniel}]
F=[Person{Robin, French}]
W=[Person{Tamara, Wyatt}, Person{Lauren, Wright}]
G=[Person{Helena, Graves}, Person{Aysha, Graham}]
J=[Person{Madeleine, Jenkins}, Person{Christina, Johnson}]
K=[Person{Jasmine, Knight}]
M=[Person{Freya, Montgomery}]

很难从这里开始,因为我需要进一步汇总上述内容以获得包含三个条目/键的地图。期望的输出:

Map<String, List<Person>> result = ...

A-H = [Person{Helena, Graves}, Person{Aysha, Graham}, Person{Melissa, Carpenter}, Person{Marie, Daniel}, Person{Robin, French}, Person{Annie, Bradley}]
I-N = [Person{Jasmine, Knight}, Person{Madeleine, Jenkins}, Person{Christina, Johnson}, Person{Freya, Montgomery}]
O-Z = [Person{Phoebe, Reyes}, Person{Tamara, Wyatt}, Person{Lacey, Todd}, Person{Heather, Parker}, Person{Lauren, Wright}]

【问题讨论】:

    标签: java java-8 java-stream groupingby


    【解决方案1】:

    您应该稍微更改分类器函数以组合一系列字符。

    另外,可能需要对 entrySet() 进行排序(或者收集到地图时使用SortedMap/TreeMap):

    myList.stream()
          .collect(Collectors.groupingBy(
              p -> p.getLastName().charAt(0) < 'I' ? "A-H" : 
                   p.getLastName().charAt(0) < 'O' ? "I-N" : "O-Z"
          ))
          .entrySet()
          .stream()
          .sorted(Map.Entry.comparingByKey())
          .forEach(System.out::println);
    

    输出:

    A-H=[Person {Helena Graves}, Person {Aysha Graham}, Person {Melissa Carpenter}, Person {Marie Daniel}, Person {Robin French}, Person {Annie Bradley}]
    I-N=[Person {Jasmine Knight}, Person {Madeleine Jenkins}, Person {Christina Johnson}, Person {Freya Montgomery}]
    O-Z=[Person {Phoebe Reyes}, Person {Tamara Wyatt}, Person {Lacey Todd}, Person {Heather Parker}, Person {Lauren Wright}]
    

    【讨论】:

    • 非常感谢。不知道我可以在groupingBy 中添加条件。学到了新的一课。谢谢。
    【解决方案2】:

    基本上,您只需要使用Collectors.groupBy(Function) 和一个将每个Person 分配到正确组的函数进行分组:

    /**
     * This method is null-friendly
     */
    String group(Person person) {
        return Optional.ofNullable(person)
            .map(Person::getFirstName)
            .filter(name -> name.length() > 0)
            .map(name -> name.charAt(0))
            .map(ch -> {
                if (ch >= 'A' && ch <= 'H') {
                    return "A-H";
                } else if (ch > 'H' && ch <= 'N') {
                    return "I-N";
                } else if (ch > 'N' && ch <= 'Z') {
                    return "O-Z";
                }
                return "*";   // In case the name starts with a character out of A-Z range
            })
            .orElse("none");  // In case there is empty/null firstName
    }
    
    Map<String, List<Person>> map = myList
            .stream()
            .collect(Collectors.groupingBy(this::group));
    

    【讨论】:

    • 非常感谢。除了一个小问题外,这很有效,但这很可能是我的错。我在this::group 处遇到编译错误,无法从静态上下文中引用。我使用 lambda p -&gt; group(p) 让它工作
    • 如果您在 static 方法中运行 Stream,则方法 group 也必须为 staticstatic String group (Person person) { ... }。然后在 Stream 中,您也可以使用方法引用(假设方法所在的 Foo 类):Collectors.groupingBy(Foo::group)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-09
    • 1970-01-01
    • 1970-01-01
    • 2020-12-14
    • 2018-08-17
    相关资源
    最近更新 更多