2

我有一个简单的课程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所有I-NO-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}]
4

2 回答 2

4

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

此外,可能需要对 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}]
于 2021-10-22T19:36:10.653 回答
3

基本上,您只需要使用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));
于 2021-10-22T19:25:33.560 回答