티스토리 뷰

728x90
반응형

그룹화

groupingBy() 연산의 결과로 그룹화 함수가 반환하는 키, 각 키에 대응하는 스트림의 모든 항목 리스트를 값으로 갖는 Map 반환

Map<Dish.Type, List<Dish>> dishesByType = menu.stream()
						.collect(groupingBy(Dish::getType));
                        
Map<CaloricLevel, List<Dish>> dishesByCaloricLevel = menu.stream().collect(	//복잡한 분류 기준이 필요한 상황
	groupingBy(dish -> {
    	if (dish.getCalories() <= 400) return CaloricLevel.DIET;
        else if (dish.getCalories() <= 700) return CaloricLevel.NORMAL;
        else return CaloricLevel.FAT;
    }));

그룹화된 요소 조작

  • filtering()은 Predicate 인수로 각 그룹의 요소와 필터링 된 요소를 재그룹화
  • 목록이 비어있는 항목도 추가
Map<Dish.Type, List<Dish>> caloricDishesByType = menu.stream().filter(dish -> dish.getCalories() > 500)
							.collect(groupingBy(Dish::getType));
//{OTHER=[french fries, pizza], MEAT=[pork, beef]}, FISH 요리가 없으면 키 자체가 사라짐

Map<Dish.Type, List<Dish>> caloricDishesByType = menu.stream().collect(
							groupingBy(Dish::getType,
                            				filtering(dish -> dish.getCalories() > 500, toList())));
//{OTHER=[french fries, pizza], MEAT=[pork, beef], FISH=[]}
  • mapping()은 매핑 함수와 각 항목에 적용한 함수를 모으는데 사용
Map<Dish.Type, List<String>> dishNamesByType = menu.stream().collect(
                            	groupingBy(Dish::getType, mapping(Dish::getName, toList())));
  • flatMapping()은  groupingBy 등의 메서드와 함께 사용되어 그룹화된 요소를 다시 플랫하게 변환할 때 유용
  • 첫번째 인자는 각 요소를 스트림으로 변환하는 함수
  • 두번째 인자는 첫번째 인자에서 반환된 스트림의 요소를 수집하는데 사용할 Collector
List<String> fruits = Arrays.asList("apple", "banana", "apricot", "grape", "blueberry");

// 각 과일을 길이에 따라 그룹화하고, 그룹화된 리스트를 플랫하게 변환하여 모든 과일을 하나의 리스트로 얻는다.
Map<Integer, List<String>> groupedByLength = fruits.stream()
        .collect(Collectors.groupingBy(String::length,
                Collectors.flatMapping(str -> Stream.of(str), Collectors.toList())));

System.out.println(groupedByLength);
//{5=[apple, grape], 6=[banana, apricot], 9=[blueberry]}

다수준 그룹화

  • Collectors.groupingBy를 중첩하여 다수준 그룹화를 수행
  • n 수준 그룹화의 결과는 n 수준 트리 구조로 표현되는 n 수준 맵이 됨
List<String> fruits = Arrays.asList("apple", "banana", "apricot", "grape", "blueberry");

// 먼저 길이로 그룹화하고, 그 다음 첫 번째 글자로 그룹화한다.
Map<Integer, Map<Character, List<String>>> groupedByLengthAndFirstChar = fruits.stream()
        .collect(Collectors.groupingBy(String::length,
                Collectors.groupingBy(str -> str.charAt(0))));

System.out.println(groupedByLengthAndFirstChar);
//{5={a=[apple], g=[grape]}, 6={b=[banana], a=[apricot]}, 9={b=[blueberry]}}

서브그룹으로 데이터 수집

  • collectingAndThen()은 Collector가 수집한 결과에 추가적인 변환을 적용하여 최종 결과를 얻을 때 유용
Map<Dish.Type, Dish> mostCaloricByType = menu.stream().collect(
		groupingBy(Dish::getType,	//분류함수
        collectionAndThen(
        	maxBy(comparingInt(Dish::getCalories)),	//감싸인 컬렉터
            Optional::get)));	//변환 함수
  • 같은 그룹으로 분류된 모든 요소에 리듀싱 작업을 수행할 때는 groupingBy에 두번째 인수로 전달한 컬렉터를 사용
Map<Dish.Type, Integer> totalCaloriesByType = menu.stream().collect(	//각 요리 그룹의 칼로리 합계
					groupingBy(Dish::getType,
                    			summingInt(Dish::getCalories));
  • mapping()은 스트림의 요소를 변환한 뒤 해당 변환된 결과를 다른 컬렉터로 수집하는 데 사용
  • 변환 함수를 적용하여 스트림의 요소를 변환한 후, 해당 변환된 결과를 다른 컬렉터로 수집하는 기능을 제공
  • 스트림의 요소를 변환하는 함수와 변환된 결과를 수집할 컬렉터를 인수로 받음
Map<Dish.Type, Set<CaloricLevel>> caloricLevelsByType = menu.stream().collect(
					groupingBy(Dish::getType, mapping(dish -> {
                                            if (dish.getCalories() <= 400) return CaloricLevel.DIET;
                                            else if (dish.getCalories() <= 700) return CaloricLevel.NORMAL;
                                            else return CaloricLevel.FAT;},
                                        toSet())));
  • toCollection()은 지정된 컬렉션 타입에 요소를 수집하는 데 사용
Map<Dish.Type, Set<CaloricLevel>> caloricLevelsByType = menu.stream().collect(
					groupingBy(Dish::getType, mapping(dish -> {
                                            if (dish.getCalories() <= 400) return CaloricLevel.DIET;
                                            else if (dish.getCalories() <= 700) return CaloricLevel.NORMAL;
                                            else return CaloricLevel.FAT;},
                                        toCollection(HashSet::new) )));

 

728x90
반응형
반응형
300x250