Group By Java 8

时间:2016-01-24 04:41:12

标签: lambda group-by java-8

假设您有一名学生注册课程

Class Student{
  ArrayList<Course> courses;
}
Class Course{
  String id;
  String name;
}

如何将groupBy函数与java 8一起用于参加特定课程的学生列表

2 个答案:

答案 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中它可以正常工作。