使用 Java 8 Streams 将 List<Object> 转换为 Map<String, Integer>,这样 String 就不是重复值
Transform a List<Object> to a Map<String, Integer> such that the String is not a duplicate value using Java 8 Streams
我们有一个Student
class如下:
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>
,以便:
- 地图不包含任何重复的学生
- 如果发现重复的学生姓名,他的分数将加上
上一次出现。
所以输出应该是:
{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));
但是合并函数不允许我连接标记,这 returns 输出为:
{abc = 30, DEF = 40}
有人可以为此提出有效的解决方案吗?
那是因为合并函数不正确,你应该改用:
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));
另一种解决方案是使用 groupingBy
和 summingInt
:
Map<String, Integer> studentMap = studentList.stream()
.collect(Collectors.groupingBy(
s -> s.getStudentName().toLowerCase(),
Collectors.summingInt(Student::getMarks)));
您的合并功能不正确。如果您更愿意使用方法参考,它可以是 (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
方法按姓名对他们进行分组,然后汇总他们的分数。
您可以使用 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}
我们有一个Student
class如下:
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>
,以便:
- 地图不包含任何重复的学生
- 如果发现重复的学生姓名,他的分数将加上 上一次出现。
所以输出应该是:
{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));
但是合并函数不允许我连接标记,这 returns 输出为:
{abc = 30, DEF = 40}
有人可以为此提出有效的解决方案吗?
那是因为合并函数不正确,你应该改用:
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));
另一种解决方案是使用 groupingBy
和 summingInt
:
Map<String, Integer> studentMap = studentList.stream()
.collect(Collectors.groupingBy(
s -> s.getStudentName().toLowerCase(),
Collectors.summingInt(Student::getMarks)));
您的合并功能不正确。如果您更愿意使用方法参考,它可以是 (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
方法按姓名对他们进行分组,然后汇总他们的分数。
您可以使用 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}