假设您有一名学生注册课程
Class Student{
ArrayList<Course> courses;
}
Class Course{
String id;
String name;
}
如何将groupBy函数与java 8一起用于参加特定课程的学生列表
答案 0 :(得分:4)
由于您希望将同一个学生分类到不同的组,groupingBy
收集器不适合(它将每个流元素完全放在一个组中)。
创建一个可变容器(如HashMap
)并通过forEach
填充它会更有效:
Map<Course, List<Student>> result = new HashMap<>();
students.forEach(student -> student.courses.forEach(
course -> result.computeIfAbsent(course, c -> new ArrayList<>()).add(student)));
如果您想使用groupingBy
,您可以分组不是学生,而是学生课程对,但您需要执行下游收集步骤:
import static java.util.stream.Collectors.*;
Map<Course, List<Student>> result = students.stream()
.<Map.Entry<Course, Student>>flatMap(
student -> student.courses.stream()
.map(course -> new AbstractMap.SimpleEntry<>(course, student)))
.collect(groupingBy(Map.Entry::getKey, mapping(Map.Entry::getValue, toList())));
看起来有点难看。我的StreamEx库为这种情况添加了一些快捷方式:
Map<Course, List<Student>> result = StreamEx.of(students)
.cross(s -> s.courses.stream()).invert().grouping();
这看起来好多了,但简单的解决方案看起来仍然更好(并且不需要第三方库)。
答案 1 :(得分:1)
我必须承认我正在使用来自@ tagir-valeev回答的想法 创建一个简单的类
public class CourseStundentPair {
private Course course;
private Student student;
public CourseStundentPair(Course course, Student student) {
this.course = course;
this.student = student;
}
...
}
这将使代码更加简洁和可读 只是出于说服我向学生添加名字字段
import static java.util.stream.Collectors.*;
public class TestCourse {
public static void main(String[] args) {
Student student1 = new Student("1", "Student1");
Student student2 = new Student("2", "Student2");
Student student3 = new Student("3", "Student3");
Student student4 = new Student("4", "Student4");
Course course1 = new Course("c1", "English");
Course course2 = new Course("c2", "Mathematics");
Course course3 = new Course("c3", "Literature");
student1.getCourses().add(course1);
student1.getCourses().add(course2);
student1.getCourses().add(course3);
student2.getCourses().add(course1);
student2.getCourses().add(course2);
student3.getCourses().add(course1);
List<Student> students = new ArrayList<>();
students.add(student1);
students.add(student2);
students.add(student3);
students.add(student4);
final Map<Course, List<Student>> courseToStudents = students.stream()
.flatMap(s -> s.getCourses().stream().map(c -> new CourseStundentPair(c,s)))
.collect(groupingBy(CourseStundentPair::getCourse,
mapping(CourseStundentPair::getStudent, toList())
)
);
for (Course course :courseToStudents.keySet()){
System.out.printf("Course %s , Students: %s \n"
,course.getName()
,courseToStudents.get(course).stream().map(Student::getName)
.collect(joining(", ")));
}
}
控制台将输出
Course English , Students: Student1, Student2, Student3
Course Literature , Students: Student1
Course Mathematics , Students: Student1, Student2
请注意,在eclipse中,IDE可能会抱怨编译错误,在Intellij中它可以正常工作。