프로그래밍 노트/JAVA

[JAVA] Stream 요소를 그룹핑해서 수집하기(Collectors.groupingBy)

깡냉쓰 2020. 1. 9. 23:02
728x90
반응형

collect()메소드는 단순히 요소를 수집하는 기능 외 컬렉션의 요소들을 그룹핑해서 Map객체를 생성하는 기능도 제공한다.
Collectors의 groupingBy() 또는 groupingByConcurrent()가 리턴하는 Collector를 매개값으로 대입하면 사용할 수 있다.
groupingBy()는 Map객체를 리턴하며, groupingByConcurrent는 ConcurrentMap을 리턴한다.

Collectors의 static method

// With a classification function as the method parameter:
// T를 K로 매핑하고, K키에 저장된 List에 T를 저장한 Map 생성
static <T,K> Collector<T,?,Map<K,List<T>>> 
  groupingBy(Function<? super T,? extends K> classifier)

// With a classification function and a second collector as method parameters:
// T를 K로 매핑하고, K키에 저장된 D객체에 T를 누적한 Map 생성
static <T,K,A,D> Collector<T,?,Map<K,D>>
  groupingBy(Function<? super T,? extends K> classifier, 
    Collector<? super T,A,D> downstream)

// With a classification function, a supplier method (that provides the Map implementation that will contain the end result), and a second collector as method parameters:
// T를 K로 매핑하고 Supplier가 제공하는 Map에서 K키에 저장된 D객체에 T를 누적
static <T,K,D,A,M extends Map<K,D>> Collector<T,?,M>
  groupingBy(Function<? super T,? extends K> classifier, 
    Supplier<M> mapFactory, Collector<? super T,A,D> downstream)

Case1. groupingBy(Function<? super T,? extends K> classifier)

학생들을 성별로 그룹핑하고 나서, 같은 그룹에 속하는 학생 List를 생성한 후,
성별을 Key로, 학생 List를 Value로 갖는 Map을 생성한다.

public class StudentMockData {
    public static final List<Student> totalList =
            Arrays.asList(
                    new Student("깡냉", 10, Student.Sex.MALE),
                    new Student("손생", 8, Student.Sex.MALE),
                    new Student("크리스챤", 5, Student.Sex.MALE),
                    new Student("원숭이", 5, Student.Sex.MALE),
                    new Student("완두콩", 0, Student.Sex.FEMALE),
                    new Student("완두콩2", 0, Student.Sex.FEMALE)
            );
}
public class GroupingExam1 {
    public static void main(String[] args) {
        List<Student> totalList = StudentMockData.totalList;

        Stream<Student> totalStream = totalList.stream();
        Function<Student, Student.Sex> classifier = Student::getSex;
        Collector<Student, ?, Map<Student.Sex, List<Student>>> collector =
                Collectors.groupingBy(classifier);

        Map<Student.Sex, List<Student>> mapBySex = totalStream.collect(collector);
        System.out.println(mapBySex);

                // 위의 코드와 같음
                mapBySex = totalList.stream()
                .collect(Collectors.groupingBy(Student::getSex));
    }
}

Student.Sex(FEMALE, MALE)이 Key가되고, 그룹핑된 List<Student>가 Value가 되는 Map을 얻을 수 있다.

Case2. groupingBy(Function<? super T,? extends K> classifier, Collector<? super T,A,D> downstream)

학생들을 점수별로 그룹핑하고 나서, 같은 그룹에 속하는 학생들의 이름 List를 생성한 후,
점수를 Key로 이름 List를 Value로 갖는 Map을 생성한다.

public static final List<Student> totalList2 =
            Arrays.asList(
                    new Student("깡냉", 10, Student.Sex.MALE, Student.City.Incheon),
                    new Student("손생", 8, Student.Sex.MALE, Student.City.Seoul),
                    new Student("크리스챤", 5, Student.Sex.MALE, Student.City.Incheon),
                    new Student("원숭이", 5, Student.Sex.MALE, Student.City.Seoul),
                    new Student("완두콩", 0, Student.Sex.FEMALE, Student.City.Incheon),
                    new Student("완두콩2", 0, Student.Sex.FEMALE, Student.City.Incheon)
            );
public class GroupingExam2 {
    public static void main(String[] args) {
        List<Student> totalList = StudentMockData.totalList2;

        Stream<Student> totalStream = totalList.stream();

        Function<Student, Student.City> classifier = Student::getCity;
        Function<Student, String> mapper = Student::getName;

        Collector<String, ?, List<String>> collector1 = Collectors.toList();
                // Collectors의 mapping() 메소드로 Student를 이름으로 매핑하고 이름을 List에 수집하는 Collector를 얻는다.
        Collector<Student, ?, List<String>> collector2 = Collectors.mapping(mapper, collector1);

        Collector<Student, ?, Map<Student.City, List<String>>> collector3 =
                Collectors.groupingBy(classifier, collector2);

        Map<Student.City, List<String>> mapByCity = totalStream.collect(collector3);
        System.out.println(mapByCity);

        mapByCity = totalList.stream()
                .collect(
                        Collectors.groupingBy(
                                Student::getCity,
                                Collectors.mapping(Student::getName, Collectors.toList())
                        )
                );
        System.out.println(mapByCity);

                // groupingBy(Function<? super T,? extends K> classifier, Supplier<M> mapFactory, Collector<? super T,A,D> downstream)
                // 위의 코드와 동일하나 TreeMap 객체를 생성해서 반환하도록 한다.
                mapByCity = totalList.stream()
                .collect(
                        Collectors.groupingBy(
                                Student::getCity,
                                TreeMap::new,
                                Collectors.mapping(Student::getName, Collectors.toList())
                        )
                );
        System.out.println(mapByCity);
    }
}
{Seoul=[손생, 원숭이], Incheon=[깡냉, 크리스챤, 완두콩, 완두콩2]}
728x90
반응형