繁体   English   中英

如何在流 groupingBy 之后聚合分组的实体

[英]How to aggregate grouped entities after stream groupingBy

我有一个简单的类人:

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

以及人员的输入列表,例如:

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")
);

现在我需要按人的姓氏的第一个字符对上面的列表进行分组,然后再次对组进行分组,以便在AH之间开始的所有姓氏都属于一个组,下一组是那些以IN开头的姓氏,最后是OZ

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

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

基本上,您只需要使用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));

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

此外,可能需要对 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}]

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM