Programming/Back-end(Java, JSP)

[Java] Comparable 정리 - 사용법, 예시코드

Sujin Lee (Daisy) 2020. 8. 14. 20:26

친구들과 알고리즘 스터디를 하다가, 2개 이상의 조건으로 정렬을 하는 문제에서 Comparable/Comparator를 사용할 일이 있었다. 

(참고문제: 백준 1181번 단어정렬 문제

Comparable/Comparator 사용법이 익숙하지 않아서 이 포스팅에서 정리하려고 한다. 

 

※ [참고] 이 포스팅에서 사용한 코드 전체는 아래의 Github url에서 보실 수 있습니다. 

https://github.com/sujinlee0616/Algorithm/blob/master/JavaExercises/sujin/format/ComparableEx.java

 

 

<Comparable>

1. Comparable ? 

 - 기본적인 정렬(int/long 오름차순, String 사전순 정렬)을 구현할 때 사용한다. 

 - Java에서 제공하는 정렬 가능한 클래스들은 모두 Comparable 인터페이스를 구현하고 있으며, 정렬 시에 이 Comparable에 맞게 정렬이 된다. 

   ex) Arrays.sort(arr); // 배열 정렬 

   ex) Collections.sort(list); // list 정렬 

 - 정렬할 객체에 Comparable 인터페이스를 implements 한 후, compareTo() 메서드를 오버라이드하여 구현한다.

   (--> 아래의 코드에서  class Book implements Comparable<Book>한 걸 볼 수 있음. ) 

 - 기본적이지 않은 정렬 (int/long 내림차순, String 사전역순, 여러개의 기준으로 정렬 등)시에는 Comparable이 아니라 Comparator를 사용하는 것이 일반적이다. ㅋComparator 설명은 이 포스팅에 정리하였다. 

 

 

예를 들어, 아래와 같은 리스트가 있다고 치자. 이 리스트는 Book 클래스로 구성되어 있는데, 이 Book 클래스는 title(책 제목), author(저자), company(출판사), year(출간년도)로 구성되어 있다. 

 

( 단순한 list (int로만 구성되었거나하는 list)를 Comparator를 이용해서 정렬하는 예제는 다루는 블로그 글이 많아서, 이 글에서는 일부러 class로 이루어진 list로 예시를 들었다. )

import java.util.ArrayList;
import java.util.Collections;

public class ComparableEx {
	public static void main(String[] args) {
		ArrayList<Book> list = new ArrayList<Book>();
		list.add(new Book("총균쇄", "제레미 다이아몬드", "문학사상", 2005));
		list.add(new Book("총균쇄", "제레미 다이아몬드", "문학사상", 2000));
		list.add(new Book("파타고니아, 파도가 칠 때는 서핑을", "이본 쉬나드", "라이팅하우스", 2020));
		list.add(new Book("파타고니아, 파도가 칠 때는 서핑을", "이본 쉬나드", "라이팅하우스", 2010));
		list.add(new Book("코스모스", "칼 세이건", "사이언스북스", 2010));
		list.add(new Book("코스모스", "칼 세이건", "사이언스북스", 2001));
		list.add(new Book("죽은 자의 집 청소", "김완", "김영사", 2020));
		list.add(new Book("동물농장", "조지 오웰", "민음사", 2007));
		list.add(new Book("동물농장", "조지 오웰", "민음사", 1988));
		list.add(new Book("침묵의 봄", "레이첼 카슨", "에코리브르", 2011));
		list.add(new Book("불안", "알랭 드 보통", "은행나무", 2012));
		list.add(new Book("불안", "알랭 드 보통", "은행나무", 2018));
		list.add(new Book("싯다르타", "헤르만 헤세", "민음사", 2002));
		list.add(new Book("싯다르타", "헤르만 헤세", "민음사", 2005));
		list.add(new Book("호모데우스", "유발 하라리", "김영사", 2017));
		
        Collections.sort(list);
		for(int i=0; i<list.size(); i++)
			System.out.println(list.get(i).getYear()+", "+list.get(i).getTitle());
	}
}

class Book implements Comparable<Book> {
    private String title;
    private String author;
    private String company;
    private int year;

    public Book(String a, String b, String c, int d) {
		this.title = a;
		this.author = b;
		this.company = c;
		this.year = d;
	}
    
    public String getTitle() {
		return title;
	}
    
    public int getYear() {
		return year;
	}
    
}

 

만약, 이 리스트를

1. 출판년도 오름차순으로 정렬하려면 어떻게 해야할까?  --> ex1)  에서 설명 

2. 책 제목 사전순으로 정렬하려면 어떻게 해야할까? --> ex2) 에서 설명 

3. 책 제목 기준으로 사전순으로 정렬하되, 만약 책 제목이 동일하다면 출판년도 오름차순으로 정렬하려면 어떻게 해야할까?

    --> ex3) 에서 설명 

 

결론은 Comparable을 이용하면 된다. 사실 3번은 Comparator를 더 많이 쓰는 것 같긴하지만, Comparable로도 해결할 수 있다. 

ex1), ex2), ex3)의 코드를 살펴보기 전에, Comparable에 대한 기초지식을 살펴보자.

 

2. Comparable이 사용하는 메소드 

 - int compareTo(Type obj) 

   --> public int compareTo(Type) 메소드를 구현하고, 내부에서 비교 처리 후 비교 결과를 int형으로 리턴한다. 

 

3. compareTo 메소드 작성법 

 - 현재 객체 < 파라미터로 넘어온 객체 : 음수 리턴 

 - 현재 객체 == 파라미터로 넘어온 객체 : 0 리턴 

 - 현재 객체 > 파라미터로 넘어온 객체 : 양수 리턴

 - 음수 또는 0이면 객체의 자리가 그대로 유지됨. 

   양수일 경우 두 객체의 자리가 바뀐다. 

 

 

ex1) 출판년도 오름차순으로 정렬 

class Book implements Comparable<Book> {
    private String title;
    private String author;
    private String company;
    private int year;

    public Book(String a, String b, String c, int d) {
		this.title = a;
		this.author = b;
		this.company = c;
		this.year = d;
	}
    
    public String getTitle() {
		return title;
	}
    
    public int getYear() {
		return year;
	}

    // ex1) 출판년도(year) 오름차순 
    public int compareTo(Book obj) {
        if (this.year == obj.year) { 
            return 0; 
            // 현재 객체 == 파라미터로 넘어온 객체 ==> 0 리턴 
        } else if(this.year < obj.year) { 
            return -1; 
            // 현재 객체 < 파라미터로 넘어온 객체 ==> 음수 리턴  ==> 자리 바뀌지 X ==> 오름차순 
        } else { 
            return 1;
            // 현재 객체 > 파라미터로 넘어온 객체 ==> 양수 리턴 ==> 자리 바뀌지 O ==> 오름차순 
        }
    }
}

출력 결과) 

 

ex2) 책 제목 사전순으로 정렬 

class Book implements Comparable<Book> {
    private String title;
    private String author;
    private String company;
    private int year;

    public Book(String a, String b, String c, int d) {
		this.title = a;
		this.author = b;
		this.company = c;
		this.year = d;
	}
    
    public String getTitle() {
		return title;
	}
    
    public int getYear() {
		return year;
	}
    
    // ex2) 책 제목 사전 순 
	public int compareTo(Book o) {
        int res = this.getTitle().compareTo(o.getTitle());
        return res;
    }
}

결과) 

 

ex3) 책 제목 사전순으로 정렬. 만약 책 제목이 같을 경우, 출간년도 오름차순으로 정렬 

class Book implements Comparable<Book> {
    private String title;
    private String author;
    private String company;
    private int year;

    public Book(String a, String b, String c, int d) {
		this.title = a;
		this.author = b;
		this.company = c;
		this.year = d;
	}
    
    public String getTitle() {
		return title;
	}
    
    public int getYear() {
		return year;
	}

	// ex3) 책 제목 사전순으로. 책 제목이 같을 경우, 출간년도 오름차순으로. <== 보통 이렇게 정렬 조건 추가하는 경우에는 Comparator 더 많이 쓰는듯...
	public int compareTo(Book o) {
        int res = this.getTitle().compareTo(o.getTitle());
        if(res==0) 
        	res = this.getYear() - o.getYear();
        	// 현재 객체 출판년도 > 파라미터로 넘어온 객체 출판년도 ==> 양수 리턴 ==> 자리 바뀌지 O ==> 오름차순 
        return res;
    }
    
}

 

결과) 

반응형