例如,我有一个学生的名单,他们的学期和科目。
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句柄)对它们进行分组时,我无法确定我需要如何做。
发布于 2017-06-29 17:56:22
一种方法是按包含所有要分组的字段的类进行分组。为了按预期工作,该类必须使用所有这些字段实现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级分组,因此返回的结构现在是列表映射的映射。如果您可以接受这种情况,即使对更多级别进行分组,也可以避免创建充当映射键的类。
发布于 2017-06-29 14:16:36
您可以创建一个计算字段,该字段是两列的组合。
Map<String, List<Student>> studlistGrouped =
studlist.stream().collect(Collectors.groupingBy(w -> w.getSubject() + "-" w.getAttendee()));编辑:
另一个更“适当”的解决方案:根据这篇博客文章,您需要定义一个可以容纳这两列的Tuple类:
class Tuple {
String subject;
String attendee;
}
Map<String, List<Student>> studlistGrouped =
studlist.stream().collect(Collectors.groupingBy(w -> new Tuple(w.getSubject(), w.getAttendee())));https://stackoverflow.com/questions/44827524
复制相似问题