woowacourse-study / 2022-modern-java-in-action

우아한테크코스 4기 모던 자바 인 액션 스터디
10 stars 4 forks source link

groupingBy와 partitioningBy 비교 #48

Open jaejae-yoo opened 2 years ago

jaejae-yoo commented 2 years ago

문제

groupingBy와 partitioningBy의 차이점 및 공통점

선정 배경

책에서 groupingBy와 partitioningBy 컬렉터의 비슷한 점에 대해 언급하고 있습니다. 둘의 비슷한 점과 차이점에 대해 더 알아보고 정리해 보고자 주제로 선정하였습니다.

관련 챕터

[6장] 스트림으로 데이터 수집 221p

jaejae-yoo commented 2 years ago

그룹화 : 스트림의 요소를 특정 기준으로 그룹화한다. 분할 : 스트림의 요소를 참, 거짓 두 그룹으로 분할하는 것이다.

1. 그룹화: gropingBy - 스트림의 요소를 Function으로 분류

그룹화

Map<Dish, Type, List<Dish>> caloricDishesByType = menu.stream()
        .collect(groupingBy(Dish::getType, filtering(dish -> getCalrories() > 500, toList())));
//caloricDishesByType : {OTHER=[french fries, pizza], MEAT=[pork, beef], FISH=[]}

스트림의 각 요리에서 Dish.Type과 일치하는 모든 요리를 추출하는 함수를 groupbingBy 메서드로 전달했다. 이 함수를 기준으로 스트림이 그룹화되므로 이를 분류함수라고 부른다.

다수준 그룹화

    Map<Dish.Type, Map<CalricLevel, List<Dish>>> dishesByTypeCaloricLevel = menu.stream().collect(
            groupingBy(Dish::getType, 
                    groupingBy(dish -> { 
                if (dish.getCalories() <= 400) 
                    return CaloricLevel.DIET; 
                else if (dish.getCalories() <= 700) 
                    return CaloricLevel.NORMAL;else return CaloricLevel.FAT; 
                    })
            )
    );
//dishesByTypeCaloricLevel : //{MEAT={DIET=[chicken], NORMAL=[beef], FAT=[pork]}, FISH={DIET=[prawns], NORMAL=[salmon]}, OTHER={...}}

2. 분할: partitioningBy - 스트림의 요소를 Predicate으로 분류

Map<Boolean, List<Dish>> partitionedMenu = menu.stream()
                .collect(partitioningBy(Dish::isVegetarian));
// {false=[pork, beef, chicken, prawns, salmon], // true=[french fires, rice, season fruit, pizza]}

분할은 프레디케이트를 분류 함수로 사용하는 특수한 그룹화 기능이다. 해당 분할 함수는 불리언을 반환하므로 맵의 키 형식은 Boolean이며 참, 거짓의 두 개의 그룹으로 분류된다.

다수준 분할

menu.stream()
        .collect(partitioningBy(Dish::isVegetarian), partitioningBy(d -> d.getCalories() > 500));
// {false={false=[chicken, prawns, salmon], true=[pork, beef]}, true={false=[rice, season fruit], true=[french fires, pizza]}}

가능할까?

menu.stream()
        .collect(partitioningBy(Dish::isVegetarian), partitioningBy(Dish::getType));

분류를 Function으로 하느냐 Predicate로 하느냐의 차이만 있을 뿐 동일하다. 스트림을 두 개의 그룹으로 나눠야 한다면 partitioningBy로 분할하는 것이 더 빠르다고 한다.