Java에서 배열의 정렬을 수행할 때 Arrays.sort()메소드를 사용하며, ArrayList를 정렬할 때에는 Collections.sort()메소드를 사용한다. 그러나 이러한 기본타입의 정렬 이외에 사용자 정의 클래스를 특정 기준(변수)에 따라 정렬해야하는 경우가 매우 많은데 이는 Comparable 인터페이스를 구현하여 수행할 수 있다.
예제를 바탕으로 설명할 예정인데, 참고한 예제는 '프로그래머스'의 '튜플'(2019 카카오 개발자 겨울 인턴십) 문제이다.
이 문제를 풀때, 원소의 숫자가 몇번 나타났는지 카운팅하여 이를 바탕으로 풀었는데 간단히 예를 들자면
주어진 입력 문자열 : "{{1,2,3},{2,1},{1,2,4,3},{2}}"
에 대해 숫자 1은 3번 나타났고, 숫자 2는 4번, 숫자 3은 2번, 숫자 4는 1번 나타났다.
따라서 정답 튜플은 카운팅 개수를 기준으로 내림차순하여 구할 수 있고, 즉 [2, 1, 3, 4] 가 된다
따라서 원소의 숫자와 해당 원소가 몇 번 나타났는지 저장할 수 있는 사용자 정의 객체가 필요했다.
그렇게 구현한 사용자 정의 객체는 다음과 같다.
public class ElementData implements Comparable<ElementData> {
int num; //원소의 숫자
int cnt; //원소의 숫자가 몇 번 나타났는지 카운팅해 저장
public ElementData(int num, int cnt) {
this.num = num;
this.cnt = cnt;
}
@Override
public int compareTo(ElementData elementData) { //내림차순 정렬
if(this.cnt < elementData.cnt) {
return 1;
} else {
return -1;
}
}
}
주 목적은 원소의 숫자가 몇 번 나타났는지 카운팅한 값(변수 cnt)을 기준으로 내림차순 하는 것이기 때문에 Comparable클래스를 implements하여 compareTo() 메소드를 오버라이딩했다.
compareTo() 메소드는 양수, 0, 음수를 리턴할 수 있는데 리턴하는 값에 따라 정렬이 달라진다.
현재 목적은 cnt값을 기준으로 내림차순 정렬하는 것이기 때문에, elementData.cnt의 값이 this.cnt보다 더 크면 둘의 자리를 바꾸도록 1를 리턴했다.
위에서 정의한 사용자 정의 객체(ElementData)를 실제로 정렬하는 코드는 다음과 같다. (정렬과 관계없는 불필요한 코드들은 생략함)
public int[] solution(String s) {
//불필요한 코드 생략
ElementData[] cntArr = new ElementData[100002];
for(int i=0; i<100002; i++) { //cnt 0으로 초기화
cntArr[i] = new ElementData(i, 0);
}
//불필요한 코드 생략
for(int i=0; i<s.length(); i++) { //숫자로 변환해서 카운팅하기
if(s.charAt(i) >= '0' && s.charAt(i) <= '9') { //숫자이면
if(tempNum == 0) { //첫번째로 시작하는 숫자이면
//불필요한 코드 생략
} else if(s.charAt(i) == ',' || s.charAt(i) == '}') {
if(tempNum != 0) { //원소 만들어서 카운팅하고 tempNum초기화
//불필요한 코드 생략
cntArr[tempNum].cnt += 1;
//불필요한 코드 생략
}
}
}
//카운팅 된 숫자로 내림차순 정렬하기
Arrays.sort(cntArr);
//불필요한 코드 생략
}
위에서 자리 바꿈에 대해서만 return을 언급했는데, 문자열 비교를 통해 compareTo()메소드에 대해 더 정확히 알아보자!
<compareTo()를 사용한 문자열 비교를 통해 return값 이해하기>
compareTo()메소드는 오름차순이 기본이다. 따라서 String은 사전순(ex. a > b > c)을 기준으로 비교한다.
String str1 = "a", String = str2 = "b"
두 문자열 변수가 있다고 하자.
str1.compareTo(str2);
는 -1을 리턴한다. 파라미터 문자열(str2)이 기준 문자열(str1)보다 사전순으로 뒤에 있기 때문이다.
str2.compareTo(str1);
는 1을 리턴한다. 파라미터 문자열(str1)이 기준 문자열(str2)보다 사전순으로 앞에 위치하기 때문이다.
str1.compareTo("a");
는 0을 리턴한다. 파라미터 문자열("a")과 기준 문자열(str1)이 같은 값을 가지기 때문(정확히 말하면 같은 객체를 참조하기 때문)이다.