java 位收藏家

java collectors with grouping by

我有下面的 MyClass 列表

public class MyClass {
  private String level;
  private String grade;
  private String value;
  
  // constructor, getters, setters
}
List<MyClass> myList = new ArrayList<>();
myList.add(new MyClass("Lv1", "A", "value"));
myList.add(new MyClass("Lv2", "B", "value"));
myList.add(new MyClass("Lv2", "B", "value"));
myList.add(new MyClass("Lv3", "C", "value"));
myList.add(new MyClass("Lv3", "D", "value"));

还有一个 grade list

List<String> gradeList = new ArrayList<>();
gradeList.add("A");
gradeList.add("B");
gradeList.add("C");
gradeList.add("D");
gradeList.add("E");

我想根据 gradeList 获取计数

格式为Map<String, Map<String, Long>>

我不知道如何将 gradeList 应用到 myList 流。

// I guess

        myList.stream().collect(Collectors.groupingBy(
            MyClass::getLevel,
            Collectors.groupingBy(
                // do something with gradeList
                , Collectors.counting())));
// expected result : 
{
  "Lv1"={"A"=1,"B"=0,"C"=0,"D"=0,"E"=0, }, 
  "Lv2"={"A"=0,"B"=2,"C"=0,"D"=0,"E"=0, }, 
  "Lv3"={"A"=0,"B"=0,"C"=1,"D"=1,"E"=0, }, 
}

我可以听听你的意见吗?

您可以链接两个 groupingBy() 收集器,但输出将不包含计数为 0 的成绩:

Map<String,Map<String,Long>> grouped =
    myList.stream().collect(Collectors.groupingBy(
        MyClass::getLevel,
        Collectors.groupingBy(
            MyClass::getGrade,
            Collectors.counting())));

您可以使用第二个语句添加计数为 0 的成绩:

grouped.forEach ((k,v)-> {gradeList.forEach (grade -> v.putIfAbsent (grade, 0L));});

第一个语句创建的groupedMap

{Lv1={A=1}, Lv3={C=1, D=1}, Lv2={B=2}}

第二个语句后的groupedMap

{Lv1={A=1, B=0, C=0, D=0, E=0}, Lv3={A=0, B=0, C=1, D=1, E=0}, Lv2={A=0, B=2, C=0, D=0, E=0}}