[Java] 람다 표현식 기반 커스텀 Comparator

상곤·2025년 4월 21일

Java

목록 보기
21/22
post-thumbnail

Java로 코딩 테스트를 치다 보면 가끔 정렬을 요구할 때가 있다.

한 가지 조건에 대한 정렬은
Collections.sort()
Collections.sort(target, Collections.reverseOrder()) 로 해결할 수 있다.

그러나 여러 가지 조건이 동시에 등장하면 어질어질해진다..

이럴 땐 단순한 정렬로는 해결할 수 없기 때문에
이번 글에서는 복잡한 조건 정렬까지 정리해보려고 한다!

기본적인 것부터 알아보자.

한 가지 기준에 대한 정렬

오름차순 정렬

숫자, 문자열 등 기본 타입Collections.sort()만 써도 된다.

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

출력해보면 이렇다.

내림차순 정렬

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

출력해보면 이렇다.

여러 가지 조건에 대한 정렬

두 가지 이상의 조건에 대해서 정렬을 할 때는 Comparator람다식을 사용해야 한다.

람다식(Lambda Expression)이란? 함수를 간단하게 표현하는 방법이다.
특히, 메서드를 한 줄로 간단히 작성할 때 주로 사용한다.
이런 형태로 쓴다. (매개변수) -> { 실행할 코드 }

Comparator란?

여러 조건을 적용해서 정렬하려면, 기준을 우리가 직접 만들어야 한다.
이때 사용하는 것이 바로 Comparator다.

Comparator
정렬 기준을 직접 정의할 수 있게 도와주는 인터페이스이다.

Java에서는 기본 정렬(한 가지 조건에 대한 오름차순이나 내림차순) 외에도,
여러 조건을 따져서 정렬하고 싶을 때
Comparator를 사용해 기준을 직접 설정할 수 있다.

이때 람다식을 사용한다.

Comparator에서 사용할 때는 람다식을 두 번째 인자에 적어줘야 한다.

Collections.sort(list, (a, b) -> {
    if (조건1(a) != 조건1(b)) {
        return 조건1(b) - 조건1(a); // 내림차순
    } else if (조건2(a) != 조건2(b)) {
        return 조건2(a) - 조건2(b); // 오름차순
    }
    return 최종 비교 결과;
});

문법은 이렇다.

조건 부분에 a와 b에 대해서 비교할 조건을 같지 않다는 조건으로 적어주고,
반환값에서

  • a - b라고 하면 오름차순,
  • b - a라고 하면 내림차순이 된다.

이걸로 봐서는 엥?

할 수도 있으니 문제를 하나 풀어보면서 예시 코드를 보자!

문제 선정

20920번: 영단어 암기는 괴로워 이 문제를 풀려면 여러 가지의 조건으로 정렬해야한다.

그래서 이 문제에 맞게 코드를 한 번 작성해보겠다!

자료구조 세팅

먼저 정렬을 하기 전에 자료구조를 살펴보자.

단어를 입력 받을 때 마다 이렇게 단어를 입력 받은 횟수를 wordCount라는 해쉬맵에 카운트해서 저장했다.

그리고 이것을 정렬과 출력할 때 사용하기 위해 words라는 리스트를 만들어서 키 값을 따로 옮겨담았다.

이제 문제의 세 가지 조건을 차례로 정렬 기준에 추가해보자.
첫 번째로 등장 횟수, 그 다음 길이, 마지막으로 알파벳 순서다.

첫 번째 조건 정렬

words리스트를 정렬할 때 wordCount해쉬 맵의 카운트 값을 사용할 것이고,
정렬된 순서대로 words를 출력하면 된다.

그럼 정렬대상을 words로 선택하고,
이 값을 순회하면서 wordCount의 키값으로 사용해서 정렬 조건을 작성하면 된다.

문제에서는 첫 번째 조건으로
1. 자주 나오는 단어일수록 앞에 배치한다.라고 했다.

wordCount에 저장된 value 값으로 비교를 통해서 정렬하면 된다.

자주 나온 순서대로 먼저 출력하라고 했으니, value값을 내림차순으로 정렬하면 된다.

Collections.sort(list, (a, b) -> {
	if (조건1(a) != 조건1(b)) {
		return 조건1(b) - 조건1(a); // 내림차순
	}

내림차순은 이렇게 하면 된다고 했다.
이거에 맞게 코드를 작성해보자.

Collections.sort(words, (a, b) -> {
	if (wordCount.get(a) != wordCount.get(b)) {
		return wordCount.get(b) - wordCount.get(a);
	}
});

물론 여기까지만 하면 else에 대한 반환값을 적어주지 않았기에 경고가 뜬다.

정렬 조건을 추가할 거니까 일단은 마저 작성해보자.

두 번째 조건 정렬

두 번째 정렬 조건은 2. 해당 단어의 길이가 길수록 앞에 배치한다. 이다.

이번에도 내림차순이기에 a와 b의 길이에 대해서 이렇게 작성하면 된다.

Collections.sort(words, (a, b) -> {
	if (wordCount.get(a) != wordCount.get(b)) {
		return wordCount.get(b) - wordCount.get(a);
	} else if (a.length() != b.length()) {
		return b.length() - a.length();
	}
});     

세 번째 조건 정렬

세 번째 정렬 조건은 3. 알파벳 사전 순으로 앞에 있는 단어일수록 앞에 배치한다. 이다.

앞선 두 조건(등장 횟수, 길이)이 모두 같을 때,
최종적으로 알파벳 순으로 비교해야 한다.

Java에서는 문자열을 비교할 때
String.compareTo() 메서드를 사용한다.

  • a.compareTo(b): 오름차순 정렬
  • b.compareTo(a): 내림차순 정렬

따라서 마지막에는 오름차순에 해당하는 a.compareTo(b)를 반환해주면 된다.

그래서 최종 코드는 이렇다.

Collections.sort(words, (a, b) -> {
    if (wordCount.get(a) != wordCount.get(b)) {
        return wordCount.get(b) - wordCount.get(a);  // 등장 횟수 내림차순
    } else if (a.length() != b.length()) {
        return b.length() - a.length();              // 길이 내림차순
    } else {
        return a.compareTo(b);                       // 알파벳 오름차순
    }
});

이제 정렬된 리스트를 순서대로 출력하면, 문제에서 요구한 단어장 순서를 완성할 수 있다!

이렇게 두 가지 이상의 조건에 대해서 정렬할 때 Comparator를 사용하면,
문제에서 요구하는 단어장 정렬을 정확히 구현할 수 있다.

다음부터 복잡한 조건 정렬이 나와도 겁먹지 말고,
필요한 기준을 하나씩 차근차근 작성해보자!

profile
🫠

0개의 댓글