从列表<Pojo> 中获取地图<String, List<String>>

Get a Map<String, List<String>> from List<Pojo>

我有一个 Student class 具有以下结构:

class Student {
    String name;
    int age;
    String grade;        
}    

我有一个 ListStudent(我们称它为 students),如下所示:

[{"Student1", 10, "A1"}, {"Student2", 12, "A2"}, {"Student1", 11, "A1"}, {"Student4", 11, "A1"}, {"Student5", 10, "A2"}, {"Student6", 10, "A1"}, {"Student2", 13, "A2"}, {"Student7", 11, "B1"}]

使用以下代码:

Map<String,List<Student>> groupedMap =
students.stream().collect(Collectors.groupingBy(Student::getGrade));

我可以得到一个 Map<String, List<Student>> 这样的:

{
"A1" : [{"Student1", 10, "A1"}, {"Student1", 11, "A1"}, {"Student4", 11, "A1"}, {"Student6", 10, "A1"}],
"A2" : [{"Student2", 12, "A2"}, {"Student5", 10, "A2"}, {"Student2", 13, "A2"}],
"B1" : [{"Student7", 11, "B1"}]
}

但是,我想要一个Map<String, List<String>>而不是上面的Map<String,List<Student>>

这个Map的“key”是一样的,就是Studentclass的“等级”属性。

这张地图的“价值”应该是所有 Students 具有该特定等级的名字的 List。还应从此“值”List 中删除重复项,因为可以有多个同名学生。另外,如果可能的话,我需要在此列表中保留插入顺序。

例如,这种情况下的输出为:

{
"A1" : ["Student1", "Student4", "Student6"],
"A2" : ["Student2", "Student5"],
"B1" : ["Student7"]
}

下面的代码会给出结果。尽管将删除重复项并在 Map 的“值”中保留插入顺序,但它仍然是 Set.

Map<String, Set<String>> groupedMap =
students.stream()
  .collect(Collectors.groupingBy(Student::getGrade,
        Collectors.mapping(Student::getName, Collectors.toCollection(LinkedHashSet::new))));

但是,如果我们只需要 List 的“值”(当然要删除重复项)而不是 Set,那么我们可以使用以下代码:

Map<String, List<String>> groupedMap =
students.stream()
  .collect(Collectors.groupingBy(Student::getGrade,
        Collectors.mapping(Student::getName,
              Collectors.collectingAndThen(
                    Collectors.toCollection(
                          LinkedHashSet::new), ArrayList::new))));

使用下游收集器将学生映射到姓名。

 students.stream()
                .collect(Collectors.groupingBy(Student::getGrade, 
                         Collectors.mapping(Student::getName, Collectors.toList())));

同时使用这种嵌套的收集器组合

Collectors.mapping(Collectors.collectingAndThen(Collectors.toCollection()))

因为 groupingBy() 的下游收集器似乎是一个合理的选择,我认为通过用 [=13= 创建的单个收集器替换它们来使这个嵌套收集器的逻辑更加透明是有意义的].

总体方法保持不变。 LinkedHashSet 在内部用作可变容器以确保唯一性并保持顺序。归约的结果类型是 ArrayList.

Map<String, List<String>> namesByGrade = students.stream()
    .collect(Collectors.groupingBy(Student::getGrade,
         Collector.of(LinkedHashSet::new,
            (Set<String> set, Student next) -> set.add(next.getName()),
            (Set<String> left, Set<String> right) -> { left.addAll(right); return left; },
            ArrayList::new)));