Array.sort()
- 배열 내에 Primitive Type을 정렬하기 위해 사용한다.
- 기본 정렬은 오름차순이다.
String arr[] = {"a", "c", "b", "e", "d"};
Arrays.sort(arr);
for(String i : arr) {
System.out.print("[" + i + "]");
}
System.out.println();
Arrays.sort(arr, Collections.reverseOrder()); //내림차순
for(String i : arr) {
System.out.print("[" + i + "]");
}
//[a][b][c][d][e]
//[e][d][c][b][a]
Comparable과 Comparator( Collection.sort() )
Comparable
일단 예시를 보고 특징을 살펴보자.
class MainClass {
public static void main(String[] args) {
ArrayList<Student> al=new ArrayList<Student>();
al.add(new Student(101,"Vijay",23));
al.add(new Student(106,"Ajay",27));
al.add(new Student(105,"Jai",21));
Collections.sort(al);
for(Student st:al){
System.out.println(st.rollno+" "+st.name+" "+st.age);
}
}
}
class Student implements Comparable<Student>{
int rollno;
String name;
int age;
Student(int rollno,String name,int age){
this.rollno=rollno;
this.name=name;
this.age=age;
}
@Override
public int compareTo(Student st){
if(age==st.age)
return 0;
else if(age>st.age)
return 1;
else
return -1;
}
}
- Student에는 각 사람의 나이 정보가 들어있는데 나이별 오름차순을 해주는 정렬이다.
- Comparable과 Comparator를 사용한다는 것은 데이터가 1개만 있을 때가 아닌 데이터가 2개 이상 들어있는 객체, 맵, 2차원 배열 등에서 정렬에 대한 기준을 마련하기 위해 사용한다.
- 해당 객체의 클래스 내에 Comparable의 compareTo를 구현해서 사용해야 한다.
- Collections.sort()를 통해 정렬한다.
- Collections.sort()는 첫번째 인자로 항상 List를 던진다. 그러면 알아서 compareTo에 정의된 규칙에 따라 정렬한다.
- return 0, 1, -1이라는 표현은 1은 단순히 양수를 표현하기 위한 것이고 -1은 음수를 표현하기 위한 것이라 숫자가 어떤 것이든 상관 없다. 그래서 아래처럼 표현해줘도 상관없다.
- 이전값과 다음값에 대한 비교를 하는데 이전값이 큰 경우에 1을 주면 오름차순 -1을 주면 내림차순이된다.
public int compareTo(Student st){
return age - st.age;
}
public int compareTo(Student st){
return (age - st.age) * -1; //내림차순
}
Comparator
Comparator는 Comparable과 정렬 방식은 비슷하지만 미세한 차이가 있다.
Comparator는 보통 Collections.sort의 2번째 인자로 쓴다. 2번째 인자는 Comparator 인터페이스의 compare를 구현해서 사용한다.
Collections.sort(list, new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
if(s1.age==s2.age)
return 0;
else if(s1.age>s2.age)
return 1;
else
return -1;
}
});
겉으로만 보면 Comparable과 같은 정렬인 것 같은데, 굳이 2번째 인자에 사용하는 이유는 위처럼 클래스 내에 compareTo가 이미 선언되어 고정되어 있으면 후에 새로운 정렬 방법(갑자기 내림차순을 하고 싶다든가)을 만들기에는 조금 까다롭다. 그럴 때 커스터마이징 된 새로운 정렬 방법을 정의할 때 사용한다.
또 HashMap에 대한 정렬인 경우에는 사용자가 정의한 클래스가 없기 때문에 Comparable을 구현해서 사용할 수 없으므로 Comparator의 compare를 구현해서 사용해야한다.
Comparator는 다양한 곳에서 사용 가능하다.
list.sort()로 Comparator 구현체를 넣어줘도 정렬이 가능하다. Arrays.sort()에도 사용 가능하다.
list.sort()를 이용한다면 Collections.sort()와 기능이 같다.
Comparator.comparing
Comparator 구현 위치에 comparing을 써서 객체의 데이터만 지정할 수 있다면 아래처럼 짧게 작성이 가능하다.
list.sort(Comparator.comparing(Student::getAge));
Comparator에 람다식 사용
List<Map.Entry<Integer, Integer>> entries = new LinkedList<>(map.entrySet());
Collections.sort(entries, (o1, o2) -> o2.getKey().compareTo(o1.getKey()));
위 코드의 특징을 알아보자.
- 위의 코드는 HashMap을 정렬하기 위해 사용하는 코드다. 위에서 설명한대로 클래스의 객체가 아니기 때문에 Comparable를 사용 할 수 없다.
- map.entrySet()으로 Set형으로 바꿔서 LinkedList 생성자의 인자로 주면 List에 전부 들어가게 된다.
- 해당 List를 Collections.sort의 첫번째 인자로 넘긴다.
- 두번째 인자는 위에 배웠던대로 Comparator을 구현해서 compare를 구현해서 사용해야 하는데 웬 람다식이 들어가서 코드가 이상해보이지만 람다식은 인터페이스에 있는 추상형 함수가 1개만 존재한다면 해당 함수를 구현해서 사용하기 때문에(모르겠으면 람다식 정리 글 참조) 더 짧게 정렬할 수 있다.
- 그리고 Integer 타입이라면 compareTo를 사용해서 0, -1, 1을 쉽게 구해서 정렬이 쉽다.
다만 이렇게 하면 람다식 특성상 메소드만을 직접 참조해서 Comparator 클래스의 기능을 이용할 수가 없다.
람다식을 이용하면 가독성이 좋은 코드로 만들 수 있긴하지만 Comparator를 직접 구현해주면 아래처럼 다중 정렬도 사용가능하다.
다중 정렬
Collections.sort(entries, new Comparator<Map.Entry<Integer, Integer>>() { //compare 인자에 대한 타입 지정 해줘야 함
@Override
public int compare(Map.Entry<Integer, Integer> o1, Map.Entry<Integer, Integer> o2) {
return o2.getKey().compareTo(o1.getKey());
}
}.thenComparing( new Comparator<Map.Entry<Integer, Integer>>() { //compare 인자에 대한 타입 지정 해줘야 함
@Override
public int compare(Map.Entry<Integer, Integer> o1, Map.Entry<Integer, Integer> o2) {
return o2.getValue().compareTo(o1.getValue());
}
}));
예를들어 thenComparing을 통해서 나이별 정렬 후 학번 순으로 정렬이 가능하다.
'☕ Java' 카테고리의 다른 글
Java에서 일급 객체(First-Class Citizen)와 일급 컬렉션(First-Class Collection)의 의미 (0) | 2022.10.25 |
---|---|
Optional의 orElse, orElseGet, orElseThrow 사용법 (0) | 2022.06.06 |
Java 문자열 메소드 속도 효율 및 차이 (0) | 2022.05.12 |
Java 8 Stream 사용법 (0) | 2022.05.10 |
Java 배열, List, Map, Set의 선언 방법과 차이 (0) | 2022.05.09 |