[자바] Comparator와 Comparable

June·2021년 1월 4일
0

자바

목록 보기
26/36

객체 정렬 예시

  • 객체를 사용자가 정의한 정렬 기준에 맞춰 정렬해야 하는 경우
    Ex) 좌표를 x좌표가 증가하는 순, x좌표가 같으면 y좌표가 감소하는 순으로 정렬
    Ex) 국어점수는 증가하는 순, 수학점수는 감소하는 순으로 정렬

객체의 정렬 기준을 명시하는 두 가지 방법

1. Interface Comparable

정의

  • 정렬 수행 시 기본적으로 적용되는 정렬 기준이 되는 메서드를 정의하는 인터페이스
  • package: java.lang.Comparable
// Integer class
public final class Integer extends Number implements Comparable<Integer> { ... }
// String class
public final class String implements java.io.Serializable, Comparable<String>, CharSequence { ... }
  • Ex) Integer, Double 클래스: 오름차순 정렬
  • Ex) String 클래스: 사전순 정렬

구현 방법
- 정렬할 객체에 Comparable interface를 implements 후, compareTo() 메서드를 오버라이드하여 구현한다.
- compareTo() 메서드 작성법
- 현재 객체 < 파라미터로 넘어온 객체: 음수 리턴
- 현재 객체 == 파라미터로 넘어온 객체: 0 리턴
- 현재 객체 > 파라미터로 넘어온 객체: 양수 리턴
- 음수 또는 0이면 객체의 자리가 그대로 유지되며, 양수인 경우에는 두 객체의 자리가 바뀐다.
사용 방법
- Arrays.sort(array)
- Collections.sort(list)

참고 Arrays.sort()와 Collections.sort()의 차이
Arrays.sort()

  • 배열 정렬의 경우
  • Ex) byte[], char[], double[], int[], Object[], T[] 등 * Object Array에서는 TimSort(Merge Sort + Insertion Sort)를 사용
  • Object Array: 새로 정의한 클래스에 대한 배열 * Primitive Array에서는 Dual Pivot QuickSort(Quick Sort + Insertion Sort)를 사용
  • Primitive Array: 기본 자료형에 대한 배열

Collections.sort()

  • List Collection 정렬의 경우
  • Ex) ArrayList, LinkedList, Vector 등 * 내부적으로 Arrays.sort()를 사용

Comparable interface를 이용한 Java 객체를 정렬

// x좌표가 증가하는 순, x좌표가 같으면 y좌표가 감소하는 순으로 정렬하라.
class Point implements Comparable<Point> {
    int x, y;

    @Override
    public int compareTo(Point p) {
        if(this.x > p.x) {
            return 1; // x에 대해서는 오름차순
        }
        else if(this.x == p.x) {
            if(this.y < p.y) { // y에 대해서는 내림차순
                return 1;
            }
        }
        return -1;
    }
}

// main에서 사용법
List<Point> pointList = new ArrayList<>();
pointList.add(new Point(x, y));
Collections.sort(pointList);

2. Interface Comparator

정의

  • 정렬 가능한 클래스(Comparable 인터페이스를 구현한 클래스)들의 기본 정렬 기준과 다르게 정렬 하고 싶을 때 사용하는 인터페이스
  • package: java.util.Comparator
    - 주로 익명 클래스로 사용된다.
    - 기본적인 정렬 방법인 오름차순 정렬을 내림차순으로 정렬할 때 많이 사용한다.
    구현 방법
  • Comparator interface를 implements 후 compare() 메서드를 오버라이드한 myComparator class를 작성한다.

compare() 메서드 작성법
- 첫 번째 파라미터로 넘어온 객체 < 두 번째 파라미터로 넘어온 객체: 음수 리턴
- 첫 번째 파라미터로 넘어온 객체 == 두 번째 파라미터로 넘어온 객체: 0 리턴
- 첫 번째 파라미터로 넘어온 객체 > 두 번째 파라미터로 넘어온 객체: 양수 리턴
- 음수 또는 0이면 객체의 자리가 그대로 유지되며, 양수인 경우에는 두 객체의 자리가 변경된다.
- 즉, Integer.compare(x, y)(오름차순 정렬)와 동일한 개념이다.
- return (x < y) ? -1 : ((x == y) ? 0 : 1);
- 내림차순 정렬의 경우 두 파라미터의 위치를 바꿔준다.
- Integer.compare(y, x)(내림차순 정렬)

사용 방법
- Arrays.sort(array, myComparator)
- Collections.sort(list, myComparator)
- Arrays.sort(), Collections.sort() 메서드는 두 번째 인자로 Comparator interface를 받을 수 있다.

참고 두 번째 인자로 Comparator interface를 받는 경우

우선 순위 큐(PriorityQueue) 생성자의 두 번째 인자로 Comparator interface를 받을 수 있다.
- PriorityQueue(int initialCapacity, Comparator<? super E> comparator)
- 지정된 Comparator의 정렬 방법에 따라 우선 순위를 할당한다.

Comparator interface를 이용한 Java 객체를 정렬

// x좌표가 증가하는 순, x좌표가 같으면 y좌표가 감소하는 순으로 정렬하라.
class MyComparator implements Comparator<Point> {
  @Override
  public int compare(Point p1, Point p2) {
    if (p1.x > p2.x) {
      return 1; // x에 대해서는 오름차순
    }
    else if (p1.x == p2.x) {
      if (p1.y < p2.y) { // y에 대해서는 내림차순
        return 1;
      }
    }
    return -1;
  }
}

// main에서 사용법
List<Point> pointList = new ArrayList<>();
pointList.add(new Point(x, y));
MyComparator myComparator = new MyComparator();
Collections.sort(pointList, myComparator);

Comparator와 Comparable은 모두 인터페이스로 컬렉션을 정렬하는데 필요한 메서드를 정의하고있다.

Comparable을 구현하고 있는 클래스들은 같은 타입의 인스턴스끼리 서로 비교할 수 있는 클래스들, 주로 Integer와 같은 wrapper 클래스와 String, Date, File과 같은 것들이며, 기본적으로 오름차순으로 정렬하게 되어있다.

compareTo()의 반환값은 int지만 실제로는 비교하는 두 객체가 같으면 0, 비교하는 값보다 작으면 음수, 크면 양수를 반환하도록 구현해야 한다. 이와 마찬가지로 compare()도 객체를 비교해서 음수, 0, 양수중의 하나를 반환하도록 구현해야한다.

Comparable을 구현한 클래스들이 기본적으로 오름차순으로 정렬되어 있지만, 내림차순으로 정렬한다던가 아니면 다른 기준에 의해서 정렬되도록 하고 싶을 때 Comparator를 구현해서 정렬기준을 제공할 수 있다.

class ComparatorEx {
    public static void main(String[] args) {
        String[] strArr = {"cat", "Dog", "lion", "tiger"};
     	Arrays.sort(strArr); //String의 Comparable 구현에 의한 정렬
        Arrays.sort(strArr, String.CASE_INSENSITIVE_ORDER); //대소문자 구문 안함
        Arrays.sort(strArr, new Descending()); //역순 정렬
    }
}
class Descending implements Comparator {
    public int compare(Object o1, Object o2) {
        if (o1 instanceof Comparable && o2 instanceof Comparable) {
            Comparable c1 = (Comparable)o1;
            Comparable c2 = (Comparable)o2;
            return c1.compareTo(c2) * -1; //-1을 곱해서 역정렬
         }
         return -1;
     }
}

1개의 댓글

comment-user-thumbnail
2021년 7월 6일

감사합니다.
도움이 많이 되었습니다.

답글 달기