使用Java 8 Streams将List <object>转换为Map <string,integer>,以使String不是重复值

时间:2019-01-20 07:21:05

标签: java list hashmap java-stream collectors

我们有一个如下的学生班:

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<String,Integer>,以便:

  1. 地图上没有任何重复的学生
  2. 如果发现重复的学生姓名,则应在学生姓名上加上 以前的事件。

因此输出应为: {ABC = 67,DEF = 40}


我已尝试解决以下问题:

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

但是merge函数不允许我连接标记,这会将输出返回为

因此输出应为: {abc = 30,DEF = 40}

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

4 个答案:

答案 0 :(得分:6)

那是因为合并功能不正确,您应该改用:

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

答案 1 :(得分:5)

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

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

答案 2 :(得分:3)

您的合并功能不正确。如果您想使用方法引用,则可以是(s1, s2) -> s1 + s2或仅仅是Integer::sum

另一种方法是不使用流:

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

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

答案 3 :(得分:0)

您可以为此使用 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}