使用Java 8 Streams将List<Object>转换为Map<String, Integer>,确保String不是重复值。

7
我们有一个如下的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<String, Integer>,满足以下条件:

  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}

有人能为此提供一个高效的解决方案吗?
4个回答

7

这是因为错误的合并函数,您应该使用以下函数:

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

5

另一种解决方案是使用groupingBysummingInt

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

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 方法按名称分组,计算他们的总分。


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}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接