java
[Stream] 그룹핑 후 정렬 처리
nari0_0
2025. 2. 7. 18:10
728x90
데이터를 그룹핑 해 그룹핑된 값으로 정렬한 후 다른 컬럼으로 정렬하는 방법 정리
ex) 학생 객체를 Grade별로 그룹화하고 정렬한 후 나이 기준으로 정렬하기
처음 작성한 코드
Comparator.comparing((Person y) -> y.getGrade().getCode()).reversed()처럼 Grade로 정렬하려는 시도는, groupingBy에서 반환되는 Map 자체를 정렬하는 방법에 맞지 않습니다.
groupingBy는 Map을 반환하므로 내부 요소들을 정렬하는 데 TreeMap을 활용해야 하는데 아래 코드는 그룹화 된 요소들을 정렬하는 것으로 의도대로 동작하지 않는 코드였습니다.
list.stream().collect(Collectors.groupingBy(Person::getGrade,
Collectors.collectingAndThen(Collectors.toList(),
x -> x.stream()
.sorted(Comparator.comparing((Person y) -> y.getGrade().getCode()).reversed()
.thenComparing(Person::getAge)).collect(Collectors.toList()))))
수정한 코드
groupingBy의 세 번째 인자에 () -> new TreeMap<>(Comparator.comparingInt(Grade::getCode))을 사용하여, Grade의 code 값에 따라서 정렬된 Map을 반환하도록 했습니다.
list.stream()
.collect(Collectors.groupingBy(
Person::getGrade, // 'grade'별로 그룹화
() -> new TreeMap<>(Comparator.comparing(Grade::getCode)), //맵의 키를 정렬하는 작업
Collectors.collectingAndThen(
Collectors.toList(), // 그룹화된 항목들을 리스트로 수집
x -> x.stream() // 그 리스트를 스트림으로 변환
.sorted(Comparator.comparing(Person::getAge)) // 그룹화 된 요소들을 정렬
.collect(Collectors.toList())
)
))
문제 해결 과정
- groupingBy()에서 반환되는 Map의 키를 정렬하려면, TreeMap을 사용해야 합니다. TreeMap은 기본적으로 키를 정렬된 상태로 유지하는 자료구조입니다. 따라서 TreeMap을 사용하여 Grade의 code 값으로 정렬된 Map을 얻을 수 있습니다.
- 그룹화된 결과의 리스트 내 요소들을 정렬하는 것은 collectingAndThen()에서 하는 일
+)
Collectors.groupingBy는 주어진 키 값(여기서는 Person::getGrade)을 기준으로 스트림을 그룹화한 후, 그 결과로 반환되는 맵의 값들이 List로 되어 있습니다.
Collectors.collectingAndThen은 스트림에서 데이터를 수집한 후, 그 결과에 대해 후속 처리를 추가할 때 사용합니다.
두 개의 인자를 받습니다:
- 첫 번째 인자 (Collector<T, A, R> downstream): 데이터를 수집할 방식입니다. 일반적으로 Collectors.toList(), Collectors.toSet() 등이 사용됩니다. 이는 스트림의 요소들을 모아서 중간 결과를 만듭니다.
- 두 번째 인자 (Function<R, R> finisher): 수집된 결과에 대해 추가적인 작업을 처리하는 함수입니다. 이 함수는 수집된 결과에 후속 처리를 수행할 수 있게 해줍니다.
728x90