例如,我有一个学生列表及其学期和科目。
Subject Semester Attendee
---------------------------------
ITB001 1 John
ITB001 1 Bob
ITB001 1 Mickey
ITB001 2 Jenny
ITB001 2 James
MKB114 1 John
MKB114 1 Erica
当我需要使用Stream api
的一个值对它们进行分组时,我可以制作类似的内容;
Map<String, List<Student>> studlistGrouped =
studlist.stream().collect(Collectors.groupingBy(w -> w.getSubject()));
它确实有效。但是,当我想用两个或多个值(如Sql句柄)对它们进行分组时,我无法弄清楚我需要做什么。
答案 0 :(得分:1)
一种方法是按类分组,该类包含您要分组的所有字段。此类必须使用所有这些字段实现hashCode
和equals
才能按预期工作。
在您的示例中,这将是:
public class SubjectAndSemester {
private final String subject;
private final int semester; // an enum sounds better
public SubjectAndSemester(String subject, int semester) {
this.subject = subject;
this.semester = semester;
}
// TODO getters and setters, hashCode and equals using both fields
}
然后,您应该在Student
类中创建此方法:
public SubjectAndSemester bySubjectAndSemester() {
return new SubjectAndSemester(subject, semester);
}
现在,您可以按如下方式进行分组:
Map<SubjectAndSemester, List<Student>> studlistGrouped = studlist.stream()
.collect(Collectors.groupingBy(Student::bySubjectAndSemester));
这会创建一个级别的学生分组。
还有另一个选项,它不要求您使用Tuple
或创建要分组的新类。我的意思是你可以通过使用下游groupingBy
收藏家来获得 n 级别的学生分组:
Map<String, Map<Integer, List<Student>>> studlistGrouped = studlist.stream()
.collect(Collectors.groupingBy(Student::getSubject,
Collectors.groupingBy(Student::getSemester)));
这会创建一个2级分组,因此返回的结构现在是列表映射的映射。如果你可以忍受这种情况,即使是对更多关卡进行分组,你也可以避免创建一个充当地图关键字的类。
答案 1 :(得分:0)
您可以创建一个计算字段,它是两列
的组合Map<String, List<Student>> studlistGrouped =
studlist.stream().collect(Collectors.groupingBy(w -> w.getSubject() + "-" w.getAttendee()));
修改强>
另一个更“合适”的解决方案:Accoridng到this blog post,你需要定义一个可以容纳两列的Tuple
类:
class Tuple {
String subject;
String attendee;
}
Map<String, List<Student>> studlistGrouped =
studlist.stream().collect(Collectors.groupingBy(w -> new Tuple(w.getSubject(), w.getAttendee())));