시발 너무 복잡ㅈ하네요;;;;;;;;;;;;;;;;;;;;;


import java.util.*;
import java.util.stream.*;

import static java.util.Comparator.*;
import static java.util.stream.Collectors.*;

class Student {
String name;
boolean isMale;
int hak;
int ban;
int score;

public 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;
}

@Override
public String toString() {
return String.format("[%s, %s, %d학년 %d, %3d]",
name, isMale ? "" : "", hak, ban, score);
}

public String getName() {
return name;
}

public boolean isMale() {
return isMale;
}

public int getHak() {
return hak;
}

public int getBan() {
return ban;
}

public int getScore() {
return score;
}

enum Level {HIGH, MID, LOW}
}


class Main {
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)
};
Map<Integer, List<Student>> StudentByClass = Stream.of(stuArr)
.collect(groupingBy(Student::getBan));

for (List<Student> i : StudentByClass.values())
for (Student j : i)
System.out.println(j);


Map<Student.Level, List<Student>> studentByScore = 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> StudentByLevel = new TreeSet<>(studentByScore.keySet());

for (Student.Level i : StudentByLevel) {
System.out.println("[" + i + "]");

for (Student j : studentByScore.get(i))
System.out.println(j);
System.out.println();
}

Map<Student.Level, Long> SumOfStudentByScore = 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 : SumOfStudentByScore.keySet())
System.out.printf("[%s] - %d, ", key, SumOfStudentByScore.get(key));
System.out.println();

Map<Integer, Map<Integer, List<Student>>> studentOfClassAndNumber = Stream.of(stuArr)
.collect(groupingBy(Student::getHak, groupingBy(Student::getBan)));

for (Map<Integer, List<Student>> i : studentOfClassAndNumber.values()) {
for (List<Student> j : i.values()) {
System.out.println();
for (Student k : j)
System.out.println(k);
System.out.println();
}
}
Map<Integer, Map<Integer, Student>> topStudentOfClassAndNum =
Stream.of(stuArr)
.collect(groupingBy(Student::getHak,
groupingBy(Student::getBan,
collectingAndThen(
maxBy(comparingInt(Student::getScore))
, Optional::get
)
)
));

for (Map<Integer, Student> i : topStudentOfClassAndNum.values()) {
for (Student j : i.values())
System.out.println(j);
System.out.println();
}
Map<String, Set<Student.Level>> studentByScoreGroup = 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> keySet = studentByScoreGroup.keySet();

for (String key : keySet)
System.out.println("[" + key + "]" + studentByScoreGroup.get(key));
}
}