티스토리 뷰

donaricano-btn
반응형

자바에서 정렬을 구현하는 Collections 클래스의 sort 메서드를 살펴보면 다음과 같은 모습입니다.

 

public static <T extends Comparable<? super T>> void sort(List<T> list) {
    list.sort(null);
}

 

이처럼 파라미터로 받은 List 객체의 sort 메서드를 실행하고 있습니다. 그럼 List 인터페이스 안에 있는 sort 메서드를 살펴 보겠습니다.

 

default void sort(Comparator<? super E> c) {
    Object[] a = this.toArray();    
    Arrays.sort(a, (Comparator) c);
    ListIterator<E> i = this.listIterator();
    for (Object e : a) {
        i.next();
        i.set((E) e);
    }
}

 

List 인터페이스에 구현된 기본 메서드인 sort 는 내부적으로 다시 Arrays 클래스의 sort 를 다시 호출하고 있는 것을 볼 수 있습니다. List 인터페이스 에서는 리스트 자료구조에 담겨있는 값을 배열로 변환할 뿐입니다.

 

int[] numbers = {5, 3, 1, 2, 4};
Arrays.sort(numbers);

List<Integer> numbers = Arrays.asList(5, 3, 1, 2, 4);
Collections.sort(numbers);

 

배열을 정렬하는 것은 위와 같이 Arrays.sort 메소드를 사용하면 됩니다. 리스트인 경우에는 Collections.sort 메서드나 리스트 자체의 sort 메서드를 사용할 수 있습니다.

 

그렇다면 원시변수가 아닌 객체를 비교한다면 어떤 기준으로 비교하게 될까요? 그리고 정렬 순서를 역순으로 바꾸고 싶다면 어떻게 해야 할까요? 이 때 사용할 수 있는 방법은 Comparable 이나 Comparator 인터페이스를 사용하는 것입니다.

 

객체 배열 또는 리스트를 정렬한다고 생각해 봅시다. 당연히 비교를 할 수 있는 규칙이 필요합니다. 만약 배열 또는 리스트 안에 있는 모든 클래스가 어떤 규칙을 통해 정려할지 합의했다면 정렬 알고리즘은 그 규칙을 통해 정렬을 수행할 것입니다. 이때 규칙을 정해 주는 것이 바로 Comparable 이나 Comparator 같은 인터페이스 입니다. 

 

클래스가 자신이 갖고 있는 객체를 정렬하기 위해서는 Comparable 인터페이스를 구현해야 합니다. 이 인터페이스는 compareTo 라는 메서드를 가지고 있고 하나의 타입 파라미터를 받아 그 타입 파라미터를 통해 비교를 하게 됩니다. 이 때 이 메서드의 결과가 양수인지 음수인지를 통해 정렬의 순서를 정하게 됩니다.

 

public class Student implements Comparable<Student> {

    public Student(int age, String name) {
        this.age = age;
        this.name = name;
    }

    int age;
    String name;

    @Override
    public int compareTo(Student other) {
        return this.age - other.age;
    }
}
List<Student> students = Arrays.asList(
        new Student(34, "Brad"),
        new Student(22, "Nicole"),
        new Student(29, "Jay"),
        new Student(20, "Tom")
);

Collections.sort(students);

 

위 코드와 같이 Student 클래스에 Comparable 인터페이스를 구현하고 compareTo 메소드를 구현하면 age 필드의 값을 기준으로 오름차순 정렬되게 됩니다. 그럼 정렬 순서를 바꾸려면 어떻게 하면 될까요? 

 

public class Student implements Comparable<Student> {

    public Student(int age, String name) {
        this.age = age;
        this.name = name;
    }

    int age;
    String name;

    @Override
    public int compareTo(Student other) {
        return other.age - this.age;
    }
}

 

위 코드 처럼 compareTo 메서드를 수정해 주면 됩니다. 원시변수 뿐 아니라 이미 compareTo 메서드가 구현된 다른 객체를 기준으로 정렬할 수도 잇습니다. 

 

public class Student implements Comparable<Student> {

    public Student(int age, String name) {
        this.age = age;
        this.name = name;
    }

    int age;
    String name;

    @Override
    public int compareTo(Student other) {
        return this.name.compareTo(other.name);
    }
}
List<Student> students = Arrays.asList(
        new Student(34, "Brad"),
        new Student(22, "Nicole"),
        new Student(29, "Jay"),
        new Student(20, "Tom")
);

Collections.sort(students);

 

위와 같이 코드를 수정하고 실행하게 되면 name 필드를 기준으로 오름차순 정렬되게 됩니다.

 

이 Comparable 인터페이스를 구현하면 해당 클래스를 정렬하는 모든 경우에 이 정렬 기준이 적용되게 됩니다. 하지만 전체 코드에서 딱 한부분에서만 정렬을 사용 하거나 정렬 기준이 다를 때가 있습니다. 그 때 사용하는 것이 바로 Comparator 인터페이스 입니다.

 

가령 위 Student 클래스를 name 필드의 길이 순서로 정렬한다고 할 때 다음과 같이 할 수 있습니다.

 

students.sort((first, second) -> first.name.length() - second.name.length());

 

람다식으로 통해 Comparator 인터페이스 내부에 있는 compare 메서드를 구현했습니다.

 

Comparator 인터페이스 안에는 이런 메서드를 반환하는 정적 고차함수가 많이 있습니다. 위에 람다식은 아래와 같이 Comparator의 정적 메서드를 통해 대체할 수 있습니다.

 

students.sort(Comparator.comparingInt(student -> student.name.length()));

 

Comparator 인터페이스에는 비교 대상이 같을 때 추가로 비교할 수 있는 방법도 있습니다. thenComparing 메소드를 사용하면 됩니다.

 

다음은 Student 클래스의 age 필드 순으로 먼저 정렬하고, age 가 같으면 이름 순으로 정렬하는 코드입니다.

 

students.sort(Comparator.comparing(Student::getAge).thenComparing(Student::getName));

 

마지막으로 오름차순과 내림차순을 정해주는 정적 메서드도 있습니다. 이름순으로 오름차순과 내림차순으로 정렬하는 코드는 다음과 같습니다.

 

students.sort(Comparator.comparing(Student::getName, Comparator.naturalOrder()));

students.sort(Comparator.comparing(Student::getName, Comparator.reverseOrder()));

 

이 외에도 null 값을 리스트의 앞이나 뒤로 보낼 수 있는 nullsFirst, nullsLast 등의 메서드가 존재합니다.

반응형
donaricano-btn
댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함