我有一个对象列表List listOfStudents: 对象:
private class Students
{
private String name;
private int numberOfTimesComeToSchool;
}
我正在尝试查找出现次数最多的学生的名字并按照我的用法进行操作:
listOfStudents.stream().map(Student::getName)collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
如果没有领带,那么我使用
Collections.max(collect.entrySet(), Map.Entry.comparingByValue()).getKey();
确定发生次数最多的名称。
但是可能会发生学生姓名的关系,在这种情况下,我想选择最多次上学的学生姓名,即有学生姓名的学生姓名。所有名称中numberOfTimesComeToSchool的最高总和。
例如:
Student 1: Name: Hello numberOfTimesComeToSchool: 1
Student 2: Name: Hello numberOfTimesComeToSchool: 4
Student 3: Name: Trial numberOfTimesComeToSchool: 2
Student 4: Name: Trial numberOfTimesComeToSchool: 2
Student 5: Name: NeedThis numberOfTimesComeToSchool: 2
Student 6: Name: NeedThis numberOfTimesComeToSchool: 2
在这种情况下,正确的答案是Hello,因为numberOfTimesComeToSchool的总和是5,而其他名称的总和只有4,即使所有名称出现的次数相同。
任何有关这方面的帮助都会被批评。
答案 0 :(得分:3)
使用.map(Student::getName)
的问题是,您丢失了有关每个学生上学次数的信息。
相反,只需在原始列表中使用groupingBy
即可获得Map<String, List<Student>>
。然后遍历地图的入口集,并通过首先比较列表的大小来找到最大条目,然后在出现平局的情况下比较numberOfTimesComeToSchool
的总和。
Map<String, List<Student>> map =
listOfStudents.stream().collect(Collectors.groupingBy(Student::getName));
Optional<String> studentName =
map.entrySet()
.stream()
.max(Comparator.<Map.Entry<String, List<Student>>>comparingInt(e -> e.getValue().size())
.thenComparingInt(e -> e.getValue().stream().mapToInt(Student::getNumberOfTimesComeToSchool).sum()))
.map(Map.Entry::getKey);
类型推断还不够强大,所以你必须在比较器中指定类型参数,这使得它很难阅读。
最后,您可以使用Collectors.collectingAndThen
:
Optional<String> studentName =
listOfStudents.stream()
.collect(collectingAndThen(groupingBy(Student::getName),
m -> m.entrySet()
.stream()
.max(Comparator.<Map.Entry<String, List<Student>>>comparingInt(e -> e.getValue().size())
.thenComparingInt(e -> e.getValue().stream().mapToInt(Student::getNumberOfTimesComeToSchool).sum()))
.map(Map.Entry::getKey)));