【问题标题】:Transform a List<Object> to a Map<String, Integer> such that the String is not a duplicate value using Java 8 Streams使用 Java 8 Streams 将 List<Object> 转换为 Map<String, Integer> 以使 String 不是重复值
【发布时间】:2019-01-20 07:21:04
【问题描述】:

我们有一个Student 类如下:

class Student {
    private int marks;
    private String studentName;

    public int getMarks() {
        return marks;
    }

    public void setMarks(int marks) {
        this.marks = marks;
    }

    public String getStudentName() {
        return studentName;
    }

    public void setStudentName(String studentName) {
        this.studentName = studentName;
    }

    public Student(String studentName, int marks) {
        this.marks = marks;
        this.studentName = studentName;
    }
}

我们的学生名单如下:

List<Student> studentList = new ArrayList<>();
studentList.add(new Student("abc", 30));
studentList.add(new Student("Abc", 32));
studentList.add(new Student("ABC", 35));
studentList.add(new Student("DEF", 40));

此列表需要转换为HashMap&lt;String, Integer&gt;,这样:

  1. 地图不包含任何重复的学生
  2. 如果发现重复的学生姓名,他的分数应添加 上一次出现。

所以输出应该是:

{ABC = 97, DEF = 40}

我已尝试通过以下方式解决此问题:

Map<String, Integer> studentMap = studentList.stream()
        .collect(Collectors.toMap(
                student -> student.getStudentName().toLowerCase(),
                student -> student.getMarks(),
                (s1, s2) -> s1,
                LinkedHashMap::new));

但合并功能不允许我连接标记,这会将输出返回为:

{abc = 30, DEF = 40}

有人可以为此提出一个有效的解决方案吗?

【问题讨论】:

    标签: java list java-stream grouping collectors


    【解决方案1】:

    这是因为合并函数不正确,您应该改用:

    Map<String, Integer> map = studentList.stream()
            .collect(Collectors.toMap(
                    student -> student.getStudentName().toLowerCase(),
                    Student::getMarks,
                    (s1, s2) -> s1 + s2, // add values when merging
                    LinkedHashMap::new));
    

    【讨论】:

      【解决方案2】:

      另一种解决方案是将groupingBysummingInt 一起使用:

      Map<String, Integer> studentMap = studentList.stream()
              .collect(Collectors.groupingBy(
                      s -> s.getStudentName().toLowerCase(),
                      Collectors.summingInt(Student::getMarks)));
      

      【讨论】:

        【解决方案3】:

        您的合并功能不正确。如果您更愿意使用方法引用,它可以是 (s1, s2) -&gt; s1 + s2 或只是 Integer::sum

        另一种方法是不使用流:

        Map<String, Integer> studentMap = new LinkedHashMap<>();
        studentList.forEach(s -> studentMap.merge(
                                 s.getStudentName().toLowerCase(),
                                 s.getMarks(),
                                 Integer::sum));
        

        这会迭代学生列表并使用Map.merge 方法按姓名对他们进行分组,并对他们的分数求和。

        【讨论】:

          【解决方案4】:

          您可以为此目的使用Collectors.groupingBy(classifier,mapFactory,downstream) 方法:

          List<Student> list = List.of(
                  new Student("abc", 30),
                  new Student("Abc", 32),
                  new Student("ABC", 35),
                  new Student("DEF", 40));
          
          Map<String, Integer> map = list.stream()
                  .collect(Collectors.groupingBy(
                          Student::getStudentName,
                          () -> new TreeMap<>(String.CASE_INSENSITIVE_ORDER),
                          Collectors.summingInt(Student::getMarks)));
          
          System.out.println(map); // {abc=97, DEF=40}
          

          【讨论】:

            猜你喜欢
            • 2023-03-26
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-03-17
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多