Lina's Toolbox

[Java] 특정 기준으로 정렬하는 법 (Comparator인터페이스 사용) / 제네릭 타입 본문

프로그래밍 언어/Java

[Java] 특정 기준으로 정렬하는 법 (Comparator인터페이스 사용) / 제네릭 타입

Woolina 2024. 10. 2. 02:13

https://kimwoolina.tistory.com/128

 

[정렬] 프로그래머스 - 가장 큰 수

0 또는 양의 정수가 주어졌을 때, 정수를 이어 붙여 만들 수 있는 가장 큰 수를 알아내 주세요.예를 들어, 주어진 정수가 [6, 10, 2]라면 [6102, 6210, 1062, 1026, 2610, 2106]를 만들 수 있고, 이중 가장 큰 수

kimwoolina.tistory.com

🔼 이 문제를 풀면서,

 

파이썬의 sorted(numbers, key=functools.cmp_to_key(custom_compare)) 처럼,

자바에도 내가 만든 특정한 기준으로 정렬을 할 수 있게 만들어주는 기능이 있지 않을까 하여 찾아보았다.

 

Collections.sort(people, new Comparator<Person>() {  // 제네릭 타입 Person(custom class)
    @Override
    public int compare(Person p1, Person p2) {  // 메서드 인자의 타입도 Person
        return p2.age - p1.age;  // 리턴 타입은 int
    }
});

<Person>은  제네릭 타입이다.

이 제네릭 타입은 Comparator가 어떤 타입의 객체를 비교하는지를 명시합니다.

 

  • Comparator<Person>
    Comparator가 Person 객체를 비교할 것임을 명시한다. 이는 두 개의 Person 객체를 비교하게 된다는 것을 뜻함.

  • compare(Person p1, Person p2): compare() 메서드는 Person 타입의 두 객체를 인수로 받는다.

  • return p2.age - p1.age: compare() 메서드는 두 Person 객체를 비교하고, 그 결과를 int로 반환한다.
    리턴 타입이 int인 이유는 비교 결과가: (이건 파이썬과 같네!)
    • 음수: 첫 번째 객체가 두 번째 객체보다 작음.
    • 양수: 첫 번째 객체가 두 번째 객체보다 큼.
    • 0: 두 객체가 같음을 의미.

제네릭이 없는 경우 (Collections.sort)

Collections.sort() 메서드에서 만약 제네릭을 사용하지 않으면, 자바는 기본적으로 모든 객체를 Object 타입으로 취급한다.

 

제네릭을 사용하지 않는 경우:

Collections.sort(people, new Comparator() { // 제네릭을 사용하지 않음 
	@Override public int compare(Object o1, Object o2) { 
    	Person p1 = (Person) o1; Person p2 = (Person) o2; 
        	return p2.age - p1.age; 
        } 
});
  • 여기서 문제점은 compare 메서드에서 Object 타입을 Person으로 명시적으로 형변환해야 한다는 것!
  • 만약 형변환이 잘못되거나 잘못된 타입이 들어오면 런타임 오류가 발생할 수 있다.

 

💡 신기한점은 return (str1 + str2).compareTo(str2 + str1);

return (str2 + str1).compareTo(str1 + str2);

로 바꿔주면 대소관계를 반대로 비교한다는 것이였다.

 

비교 순서만 바꿔주는 게 아닌가..? 했는데,

비교 순서를 바꾸는 것만으로도 정렬 방식이 바뀌었다.

 

return (str1 + str2).compareTo(str2 + str1);

(str1 + str2)가 (str2 + str1)보다 클 경우, num1이 num2보다 크다는 것을 의미.

즉, num1이 더 앞에 오게 된다.

이 경우 더 작은 수가 먼저 배치됨

 

수정된 비교 방식

return (str2 + str1).compareTo(str1 + str2);

이 방식에서는 (str2 + str1)이 (str1 + str2)보다 클 경우, num2가 num1보다 크다고 판단한다.

즉, num2가 더 앞에 배치되어 더 큰 수를 생성하게 된다.

 

예를 들어 num1 = 9num2 = 34라고 가정해보면:

  • 기존 비교:
    • (str1 + str2): 934
    • (str2 + str1): 349
    • 934 > 349 이므로 num1이 먼저 배치된다.
  • 수정된 비교:
    • (str2 + str1): 349
    • (str1 + str2): 934
    • 349 < 934 이므로 num2가 먼저 배치된다.

이렇게 비교 방식을 바꾸는 것만으로 원하는 정렬을 구현할 수 있었다.

간단한 변경으로 큰 수를 만들 수 있는 정렬 방식이 가능해지는 것!


 

🤔 혹은 파이썬 처럼

sorted_numbers = sorted(numbers, key=functools.cmp_to_key(custom_compare), reverse=True)

 

여기서 reverse=True같은 기능은 없을까?

 

Comparator와 Reverse Order 사용

정렬을 내림차순으로 진행하고 싶다면, Comparator를 사용하여 정렬 후,

Collections.reverse(numList)로 결과를 뒤집는 방법도 있다!

// 특정 기준으로 정렬 (내림차순)
Collections.sort(numList, (num1, num2) -> {
    String str1 = Integer.toString(num1);
    String str2 = Integer.toString(num2);
    return (str1 + str2).compareTo(str2 + str1);
});

// 정렬된 리스트를 반전
Collections.reverse(numList);

'프로그래밍 언어 > Java' 카테고리의 다른 글

[Java] StringBuilder를 사용하는 이유  (1) 2024.10.01