객체 정렬

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        ArrayList<Agent> agents= new ArrayList<>();
        // Please write your code here.
        for(int i= 0;i<5;i++){
            String[] splits = sc.nextLine().split(" ");

            agents.add(new Agent(splits[0],Integer.valueOf(splits[1])));
        }

        agents.sort(Comparator.comparingInt(agent -> agent.score));

        System.out.println(agents.get(0).name + " " + agents.get(0).score);

    }

    static class Agent {
        String name;

        int score;

        Agent(String name, int score){
            this.name = name;
            this.score = score;
        } 

        
    }
}

네, 지금까지 논의한 Comparator와 Java 정렬 관련 개념을 코딩테스트 실전 관점에서 최종적으로 정리해 드리겠습니다.


## 1. 기본 정렬: 람다 vs Comparator.comparing

단일 조건으로 정렬할 때 두 가지 방법이 있습니다.

  • 람다 표현식: (o1, o2) -> o1.score - o2.score

    • 언제: 정수 빼기처럼 아주 간단한 비교 로직일 때 가장 빠르고 간결합니다.

    • 주의: Integer.compare(a, b)를 사용하는 것이 오버플로우에 안전합니다. a - b는 오버플로우 위험이 있습니다.

  • Comparator.comparing(): Comparator.comparing(User::getScore)

    • 언제: 객체의 특정 필드(Key)를 기준으로 정렬할 때 항상 이 방법을 추천합니다.

    • 코테 팁: 코드가 더 명확해지고(getScore로 비교한다는 의도), reversed()thenComparing으로 확장하기 쉽습니다. 특별한 이유가 없다면 comparing으로 시작하는 습관을 들이는 것이 좋습니다.


## 2. 복합 정렬: thenComparing으로 조건을 엮어라

코딩테스트 정렬 문제의 핵심입니다. "점수 내림차순, 같다면 이름 오름차순"과 같은 다중 조건이 나오면 if-else 람다보다 thenComparing이 압도적으로 유리합니다.

  • 나쁜 습관: if-else로 직접 조건 분기하는 람다

    Java

    이 방식은 코드가 길어지고, 조건을 추가/변경하기 어려우며, 실수할 확률이 높습니다.

  • 좋은 습관: comparingthenComparing 연결(Chaining)

    Java

    코테 팁: 다중 조건 정렬 문제가 나오면, 반사적으로 comparing().thenComparing() 체인을 떠올리세요. 이것이 시간 단축과 실수를 줄이는 가장 확실한 방법입니다.


## 3. 타입 추론: 언제 (Type o)를 써야 하는가?

람다 파라미터의 타입을 언제 명시하고 생략하는지에 대한 규칙입니다.

  • 타입 생략 가능 (o -> ...):

    1. stream.sorted((o1, o2) -> ...) 처럼 스트림에서 바로 호출될 때

    2. .thenComparing(o -> ...) 처럼 이미 타입이 결정된 Comparator에 연결될 때

    컴파일러가 문맥을 통해 파라미터의 타입을 이미 알고 있는 경우입니다.

  • 타입 명시 필요 ((int[] o) -> ...):

    1. Comparator.comparingInt((int[] o) -> o[1]) 처럼, 체인이 시작되는 제네릭 정적 메서드에서 컴파일러가 타입을 추론할 힌트가 부족할 때.

    코테 팁: Comparator.comparing...으로 코드를 작성하다가 컴파일 에러가 발생하면, 가장 먼저 첫 번째 람다에 타입을 명시해 보세요. 대부분의 경우 이 문제일 가능성이 높습니다.


## 최종 정리: 코딩테스트 정렬 만능 템플릿

아래 템플릿은 지금까지의 모든 개념을 종합한 것입니다. 이 구조만 기억하면 대부분의 객체 정렬 문제를 해결할 수 있습니다.

문제: Song 객체 리스트를 다음 규칙에 따라 정렬하라.

  1. 재생 횟수(plays)가 많은 순서 (내림차순)

  2. 재생 횟수가 같다면, 고유 번호(id)가 낮은 순서 (오름차순)

Java

Last updated