1. 스트림의 그룹화와 분할
- partitioningBy()는 스트림을 2분할한다.
Collector partitioningBy(Predicate predicate)
Collector partitioningBy(Predicate predicate, Collector downstream)
- groupingBy()는 스트림을 n분할한다.
Collector groupingBy(Function classifier)
Collector groupingBy(Function classifier, Collector downstream)
Collector groupingBy(Function classifier, Supplier mapFactory, Collector downstream)
2. 스트림의 분할 - partitioningBy()
- 스트림의 요소를 2분할
Map<Boolean, List<Student>> stuBySex = stuStream
.collect(partitioningBy(Student::isMale)); // 학생들을 성별로 분할
List<Student> maleStudent = stuBySet.get(true); // Map에서 남학생 목록을 얻는다.
List<Student> femaleStudent = stuBySet.get(false); // Map에서 여학생 목록을 얻는다.
Map<Boolean, Long> stuNumBySex = stuStream
.collect(partitioningBy(Student::isMale, counting())); // 분할 + 통계
System.out.println("남학생 수 :"+ stuNumBySet.get(true)); // 남학생 수 :8
System.out.println("여학생 수 :"+ stuNumBySet.get(false)); // 여학생 수 :10
Map<Boolean, Optional<Student>> topScoreBySex = stuStream // 분할 + 통계
.collect(partitioningBy(Student::isMale, maxBy(comparingInt(Student::getScore))));
System.out.println("남학생 1등 :"+ topScoreBySex.get(true);
// 남학생 1등 :Optional[[나자바, 남, 1, 1, 300]]
System.out.println("여학생 1등 :"+ topScoreBySex.get(false);
// 여학생 1등 :Optional[[김자바, 여, 1, 1, 250]]
Map<Boolean, Map<Boolean, List<Student>>> failedStuBySex = stuStream // 다중 분할
.collect(partitioningBy(Student::isMale, // 1. 성별로 분할(남/녀)
partitioningBy(s -> s.getScore() < 150))); // 2. 성적으로 분할(불합격/합격)
List<Student> failedMaleStu = failedStuBySex.get(true).get(true);
List<Student> failedFemaleStu = failedStuBySex.get(false).get(true);
3. 예제
class Student {
String name;
boolean isMale; // 성별
int hak; // 학년
int ban; // 반
int score;
Student(String name, boolean isMale, int hak, int ban, int score) {
this.name = name;
this.isMale = isMale;
this.hak = hak;
this.ban = ban;
this.score = score;
}
String getName() {return name;}
boolean isMale() {return isMale;}
int getHak() {return hak;}
int getBan() {return ban;}
int getScore() {return score;}
public String toString() {
return String.format("[%s, %s, %d학년%d반, %3d점]",
name, isMale? "남":"여", hak, ban, score);
}
//groupingBy()에서 사용
enum Level {HIGH, MID, LOW} // 성적을 상, 중, 하 세 단계로 분류
}
public class Ex01_05 {
public static void main(String[] args) {
Student[] stuArr = {
new Student("나자바", true, 1,1,300),
new Student("김지미", false, 1,1,250),
new Student("김자바", true, 1,1,200),
new Student("이지미", false, 1,2,150),
new Student("남자바", true, 1,2,100),
new Student("안지미", false, 1,2, 50),
new Student("황지미", false, 1,3,100),
new Student("강지미", false, 1,3,150),
new Student("이자바", true, 1,3,200),
new Student("나자바", true, 2,1,300),
new Student("김지미", false, 2,1,250),
new Student("김자바", true, 2,1,200),
new Student("이지미", false, 2,2,150),
new Student("남자바", true, 2,2,100),
new Student("안지미", false, 2,2, 50),
new Student("황지미", false, 2,3,100),
new Student("강지미", false, 2,3,150),
new Student("이자바", true, 2,3,200),
};
System.out.printf("1. 단순분할(성별로 분할)%n");
Map<Boolean, List<Student>> stuBySex = Stream.of(stuArr)
.collect(partitioningBy(Student::isMale));
List<Student> maleStudent = stuBySex.get(true);
List<Student> femaleStudent = stuBySex.get(false);
for(Student s : maleStudent) System.out.println(s);
for(Student s : femaleStudent) System.out.println(s);
System.out.printf("%n2. 단순분할+통계(성별 학생수)%n");
Map<Boolean, Long> stuNumBySex = Stream.of(stuArr)
.collect(partitioningBy(Student::isMale, counting()));
System.out.println("남학생 수 :"+stuNumBySex.get(true));
System.out.println("여학생 수 :"+stuNumBySex.get(false));
System.out.printf("%n3. 단순분할+통계(성별 1등)%n");
Map<Boolean, Optional<Student>> topScoreBySex = Stream.of(stuArr)
.collect(partitioningBy(Student::isMale,
maxBy(comparingInt(Student::getScore))
));
System.out.println("남학생 1등:"+topScoreBySex.get(true));
System.out.println("여학생 1등:"+topScoreBySex.get(false));
Map<Boolean, Student> topScoreBySex2 = Stream.of(stuArr)
.collect(partitioningBy(Student::isMale,
collectingAndThen(
maxBy(comparingInt(Student::getScore)), Optional::get
)
));
System.out.println("남학생 1등"+topScoreBySex2.get(true));
System.out.println("여학생 1등"+topScoreBySex2.get(false));
System.out.printf("%n4. 다중분할(성별 불합격자, 100점 이하)%n");
Map<Boolean, Map<Boolean, List<Student>>> failedStuBySex =
Stream.of(stuArr).collect(partitioningBy(Student::isMale,
partitioningBy(s->s.getScore() <= 100))
);
List<Student> failedMaleStu = failedStuBySex.get(true).get(true);
List<Student> failedFemaleStu = failedStuBySex.get(false).get(true);
for(Student s : failedMaleStu) System.out.println(s);
for(Student s : failedFemaleStu) System.out.println(s);
}
}
4. 스트림의 그룹화 - groupingBy()
- 스트림의 요소를 그룹화
Map<Integer, List<Student>> stuByBan = stuStream // 학생을 반별로 그룹화
.collect(groupingBy(Student::getBan, toList()); // toList() 생략가능
Map<Integer, Map<Integer, List<Student>>> stuByHakAndBan = stuStream // 다중 그룹화
.collect(groupingBy(Student::getHak, // 1. 학년별 그룹화
groupingBy(Student::getBan) // 2. 반별 그룹화
));
Map<Integer, Map<Integer, Set<Student.Level>>> stuByHakAndBan = stuStream
.collect(
groupingBy(Student::getHak, groupingBy(Student::getBan, // 다중 그룹화(학년별, 반별)
mapping(s->{ // 성적등급(Level)으로 변환 List<Student> -> Set<Student.Level>
if(s.getScore() >= 200) return Student.Level.HIGH;
else if(s.getScore() >= 100) return Student.Level.MID;
else return Student.Level.LOW;
} , toSet()) // mapping()
))
);
5. 예제
class Student {
String name;
boolean isMale; // 성별
int hak; // 학년
int ban; // 반
int score;
Student(String name, boolean isMale, int hak, int ban, int score) {
this.name = name;
this.isMale = isMale;
this.hak = hak;
this.ban = ban;
this.score = score;
}
String getName() {return name;}
boolean isMale() {return isMale;}
int getHak() {return hak;}
int getBan() {return ban;}
int getScore() {return score;}
public String toString() {
return String.format("[%s, %s, %d학년%d반, %3d점]",
name, isMale? "남":"여", hak, ban, score);
}
//groupingBy()에서 사용
enum Level {HIGH, MID, LOW} // 성적을 상, 중, 하 세 단계로 분류
}
public class Ex02_01 {
public static void main(String[] args) {
Student[] stuArr = {
new Student("나자바", true, 1,1,300),
new Student("김지미", false, 1,1,250),
new Student("김자바", true, 1,1,200),
new Student("이지미", false, 1,2,150),
new Student("남자바", true, 1,2,100),
new Student("안지미", false, 1,2, 50),
new Student("황지미", false, 1,3,100),
new Student("강지미", false, 1,3,150),
new Student("이자바", true, 1,3,200),
new Student("나자바", true, 2,1,300),
new Student("김지미", false, 2,1,250),
new Student("김자바", true, 2,1,200),
new Student("이지미", false, 2,2,150),
new Student("남자바", true, 2,2,100),
new Student("안지미", false, 2,2, 50),
new Student("황지미", false, 2,3,100),
new Student("강지미", false, 2,3,150),
new Student("이자바", true, 2,3,200),
};
System.out.printf("1. 단순그룹화(반별로 그룹화)%n");
Map<Integer, List<Student>> stuByBan = Stream.of(stuArr)
.collect(groupingBy(Student::getBan));
for(List<Student> ban : stuByBan.values()){
for (Student s : ban) {
System.out.println(s);
}
}
System.out.printf("%n2. 단순그룹화(성적별로 그룹화)%n");
Map<Student.Level, List<Student>> stuByLevel = Stream.of(stuArr)
.collect(groupingBy(s->{
if(s.getScore() >= 200) return Student.Level.HIGH;
else if(s.getScore() >= 100) return Student.Level.MID;
else return Student.Level.LOW;
}));
TreeSet<Student.Level> keySet = new TreeSet<>(stuByLevel.keySet());
for (Student.Level key : keySet) {
System.out.println("["+key+"]");
for (Student s : stuByLevel.get(key)) {
System.out.println(s);
}
System.out.println();
}
System.out.printf("%n3. 단순그룹화 + 통계(성적별 학생수)%n");
Map<Student.Level, Long> stuCntByLevel = Stream.of(stuArr)
.collect(groupingBy(s -> {
if(s.getScore() >= 200) return Student.Level.HIGH;
else if(s.getScore() >= 100) return Student.Level.MID;
else return Student.Level.LOW;
}, counting()));
for (Student.Level key : stuCntByLevel.keySet()) {
System.out.printf("[%s] - %d명, ", key, stuCntByLevel.get(key));
System.out.println();
}
System.out.printf("%n4. 다중그룹화(학년별, 반별)");
Map<Integer, Map<Integer, List<Student>>> stuByHakAndBan =
Stream.of(stuArr)
.collect(groupingBy(Student::getHak,
groupingBy(Student::getBan)
));
for (Map<Integer, List<Student>> hak : stuByHakAndBan.values()) {
for (List<Student> ban : hak.values()) {
System.out.println();
for (Student s : ban)
System.out.println(s);
}
}
System.out.printf("%n5. 다중그룹화+통계(학년별, 반별1등)%n");
Map<Integer, Map<Integer, Student>> topStuByHakAndBan =
Stream.of(stuArr)
.collect(groupingBy(Student::getHak,
groupingBy(Student::getBan,
collectingAndThen(
maxBy(comparingInt(Student::getScore))
, Optional::get
)
)
));
for(Map<Integer, Student> ban : topStuByHakAndBan.values())
for(Student s : ban.values())
System.out.println(s);
System.out.printf("%n6. 다중그룹화+통계(학년별, 반별 성적그룹)%n");
Map<String, Set<Student.Level>> stuByScoreGroup = Stream.of(stuArr)
.collect(groupingBy(s->s.getHak() + "-" + s.getBan(),
mapping(s -> {
if(s.getScore() >= 200) return Student.Level.HIGH;
else if(s.getScore() >= 100) return Student.Level.MID;
else return Student.Level.LOW;
} , toSet())
));
Set<String> keySet2 = stuByScoreGroup.keySet();
for (String key : keySet2) {
System.out.println("["+key+"]" + stuByScoreGroup.get(key));
}
}
}
'Java' 카테고리의 다른 글
148. collect()와 Collectors - 패스트캠퍼스 백엔드 부트캠프 3기 (0) | 2025.01.12 |
---|---|
147. 스트림의 최종연산 - 패스트캠퍼스 백엔드 부트캠프 3기 (0) | 2025.01.12 |
146. Optional<T> - 패스트캠퍼스 백엔드 부트캠프 3기 (1) | 2025.01.12 |
145. 스트림의 중간연산(2) - 패스트캠퍼스 백엔드 부트캠프 3기 (0) | 2025.01.11 |
144. 스트림의 중간연산 - 패스트캠퍼스 백엔드 부트캠프 3기 (0) | 2025.01.10 |