-
[ch11 JAVA ] Comparator와 Comparable 비교, 배열 정렬하기프로그래밍 언어/JAVA 2022. 8. 5. 12:53
comparator 와 comparable
comparator 와 comparable은 모두 인터페이스로 컬렉션을 정렬하는데 필요한 메서드를 정의하고 있으며, Comparable을 구현하고 있는 클래스들은 같은 타입의 인스턴스끼리 서로 비교할 수 있는 클래스들을, 주로 Integer와 같은 Wrapper 클래스와 String, Date, File과 같은 것들이며 기본적으로, 오름차순, 즉 작은 값에서부터 큰 값의 순으로 정렬되도록 구현되어 있다.
그래서 comparable을 찾아보면, 이를 구현한 클래스의 목록을 볼 수 있다.
public interface Comparator {
int compare(Object o1, Object o2); // o1과 o2를 비교
boolean equals(Object obj);
}
public interface Comparable{
int compareTo(Object o); //객체 자신(this)과 o를 비교
}compare()와 compareTo()는 선언형태와 이름이 약간 다를 뿐 두 객체를 비교한다는 것은 같은 기능을 목적으로 고안된 것이다. compareTo()의 반환값은 int이지만 실제로 비교하는 두 객체가 같으면 0, 비교하는 값보다 작으면 음수, 크면 양수 중의 하나를 반환하도록 구현해야 한다.
Comparable : 기본 정렬기준을 구현하는데 사용
Comparator : 기본 정렬기준 외에 다른 기준으로 정렬하고자 할 때 사용equals 메서드는 모든 클래스가 가지고 있는 공통 메서드이지만, Comparator를 구현하는 클래스는 오버라이딩이 필요할 수도 있다는 것을 알리기 위해서 정의할 뿐, 그냥 compare(Object o1, Object o2)만 구현하면 된다.
<예제 1번 >
package ch11; import java.util.Arrays; import java.util.Comparator; public class Ex11_7 { public static void main(String[] args) { String [] strArr = {"cat", "Dog", "lion", "tiger"}; Arrays.sort(strArr); //String의 comparable 구현에 의한 정렬 //별 다른 정렬의 기준 없이 그냥 객체 자신들과 비교해서 오름차순으로 정렬한 것. System.out.println("strArr = " + Arrays.toString(strArr)); Arrays.sort(strArr,String.CASE_INSENSITIVE_ORDER); //대소문자 구분안함 System.out.println("strArr = " + Arrays.toString(strArr)); Arrays.sort(strArr, new Descending()); //역순 정렬 System.out.println("strArr = " + Arrays.toString(strArr)); } } class Descending implements Comparator{ @Override public int compare(Object o1, Object o2) { if(o1 instanceof Comparable && o2 instanceof Comparable) { Comparable c1 = (Comparable)o1; Comparable c2 = (Comparable)o2; //compareTo 메서드를 이용해서 비교하려고 하는 그 주 객체 기준이 되는 객체는 //Comparable 형이어야 한다. 따라서 c1을 형변환한 것 return c1.compareTo(c2) * -1; } return -1; } }
Arrays.sort()는 배열을 정렬할 때, Comparator를 지정해주지 않으면 저장하는 객체에 구현된 내용에 따라 정렬된다.
static void sort(Object [] a) //객체 배열에 저장된 객체가 구현한 Comparable에 의한 정렬
static void sort(Object [] a, Comparator c) //지정한 Comparator에 의한 정렬Stirng의 Comparable구현은 문자열이 사전 순으로 정렬되도록 작성되어 있다. 즉) 오름차순 정렬은 공백, 숫자, 대문자, 소문자 순으로 정렬되는 것을 의미한다. 정확히 말하면 유니코드의 순서가 작은 값에서부터 큰 값으로 정렬되는 것이다.
Integer와 Comparable
Arrays.sort()와 같은 메서드가 정렬을 수행하는 과정에서, compareTo()를 호출한다.
public int compareTo(Integer anotherInteger) {
int thisVal = this.value;
int anotherVal = anotherInteger.value;
//왼쪽값이 크면 음수, 같으면 0, 왼쪽값이 작으면 양수를 반환한다.
return thisVal - another; //내림차순의 경우 반대로 뺄셈하면 된다.
}이미 Array.sort()와 같은 메서드의 정렬 알고리즘은 훌륭하게 잘 작성되어 있으므로, 위와 같이 compareTo()를 수현해서 어떤 비교기준으로 정렬하면 된다.
<예제 2번>
package ch11; import java.util.Arrays; import java.util.Comparator; public class Ex11_8 { public static void main(String[] args) { Integer [] arr = {30, 50, 10, 40, 20}; Arrays.sort(arr); System.out.println(Arrays.toString(arr)); //sort(Object [] objArr, Comparator c) Arrays.sort(arr, new DescComp()); System.out.println(Arrays.toString(arr)); } } class DescComp implements Comparator{ public int compare(Object o1, Object o2) { if(!(o1 instanceof Integer && o2 instanceof Integer)) return -1; //Integer가 아니면 비교하지 않고 -1 반환 Integer i1 = (Integer)o1; Integer i2 = (Integer)o2; //return i2-i; 또는 return i2.compareTo(i);도 가능 return i1.compareTo(i2) *-1; } }
정렬할 때는 항상 정렬 기준이 필요하다. Arrays.sort()로 정렬할 때 아무런 정렬 기준을 주지 않았는데도 정렬이 되는 이유는 배열 arr에 저장된 Integer가 내부에 정렬 기준을 가지고 있기 때문이다.
Collection과 Collections
Collection은 인터페이스이고 Collections는 클래스이다.
이 개념은 갖고 있었지만 collections.sort(list); 이 문장에서 급 의문이 생겼다.
위의 그림을 살펴보면 둘의 차이는 엄연히 다르다는 걸 다시 한번 알 수 있다.
Collection은 Set이나 List, Queue와 같이 자바에서 제공하는 인터페이스의 부모 인터페이스이다. Collections는 Collection을 가지고 놀기 위한 클래스이다.
<예제 3번>
package ch11; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; class Student implements Comparable { String name; int ban; int no; int kor, eng, math; Student(String name, int ban, int no, int kor, int eng, int math){ this.name = name; this.ban = ban; this.no = no; this.kor = kor; this.eng = eng; this.math = math; } int getTotal() { return kor + eng + math; } float getAverage() { return (int)( (getTotal() / 3f)*10+0.5)/10f; } public String toString() { return name + "," +"(" + ban +"," + no + "," +getTotal() +", "+ getAverage() + ")"; } @Override public int compareTo(Object o) { if(o instanceof Student) { Student s = (Student) o; return name.compareTo(s.name); }else { return -1; } } } class Exercise11_3 { public static void main(String[] args) { ArrayList list = new ArrayList(); list.add(new Student("홍길동", 1,3,100,100,100)); list.add(new Student("이자바", 3, 1,80,100,70)); list.add(new Student("김자바", 1,2,100,100,60)); list.add(new Student("안자바", 2,2,100,80,60)); list.add(new Student("남궁성", 1,1,90,100,60)); //Arrays.sort(arr)는 숫자 배열의 정렬 Collections.sort(list); //컬렉션에 저장되어 있는 값을 정렬 매개변수로 List를 받는다. Iterator it = list.iterator(); while(it.hasNext()) { System.out.println(it.next()); } } }
Student 클래스를 이름(name)으로 정렬 기준을 지정해서 구현한 것이다. 원래는 입력한 대로 값이 나오지만 public int compareTo(Object o) 를 오버라이딩 해줌으로써 이름 순서대로 값이 정렬된 걸 확인할 수 있다.
<예제 4번>
package ch11; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; class Student{ String name; int ban; int no; int kor, eng, math; Student(String name, int ban, int no, int kor, int eng, int math){ this.name = name; this.ban = ban; this.no = no; this.kor = kor; this.eng = eng; this.math = math; } int getTotal() { return kor + eng + math; } float getAverage() { return (int)( (getTotal() / 3f)*10+0.5)/10f; } public String toString() { return name + "," +"(" + ban +"," + no + "," +getTotal() +", "+ getAverage() + ")"; } } class BanNoAscending implements Comparator { @Override public int compare(Object o1, Object o2) { if(!(o1 instanceof Student && o2 instanceof Student) ) return -1; Student s1 = (Student)o1; Student s2 = (Student)o2; int result = s1.ban - s2.ban; if(result ==0 ) { return s1.no - s2.no; }else { return result; } } } class Exercise11_3 { public static void main(String[] args) { ArrayList list = new ArrayList(); list.add(new Student("홍길동", 1,3,100,100,100)); list.add(new Student("이자바", 3, 1,80,100,70)); list.add(new Student("김자바", 1,2,100,100,60)); list.add(new Student("안자바", 2,2,100,80,60)); list.add(new Student("남궁성", 1,1,90,100,60)); Collections.sort(list, new BanNoAscending()); Iterator it = list.iterator(); while(it.hasNext()) { System.out.println(it.next()); } } }
BanNoAscending 클래스를 완성해서 ArrayList에 담긴 Student 인스턴스들이 반(ban)과 번호(no)로 오름차순 되게 정렬하는 문제이다. 만약 반이 같은 경우 번호를 비교해서 정렬한다. 비교할 대상인 o1과 o2를 Student 형으로 형변환해서 no와 ban 값을 비교할 수 있게 하였다.
반응형'프로그래밍 언어 > JAVA' 카테고리의 다른 글
[ch14 람다식] 작성법 예제, 함수형 인터페이스(Functional Interface) (0) 2022.09.27 [JAVA] JVM이란? 자바 가성 머신 실행과정, 구조 알아보기 (0) 2022.09.19 [ch11 컬렉션 프레임웍] HashSet & HashMap의 메서드 및 사용법 (0) 2022.08.04 [ch9 JAVA] StringBuffer 클래스의 생성자와 메서드 알아보기 (0) 2022.08.04 [ch9 JAVA] String 클래스 생성자 & String, new String() 차이 (0) 2022.08.04