정렬(Comparable, Comparator)

정렬(Comparable, Comparator)

  • 정렬

    • 정렬 대상 클래스

        public class Player {
            private String name;
            private int score;
      
            public Player(String name, int score) {
                this.name = name;
                this.score = score;
            }
      
            // Getters, Setters 생략
        }
      
        List<Player> players = new ArrayList<>();
        players.add(new Player("Alice", 899));
        players.add(new Player("Bob", 982));
        players.add(new Player("Chloe", 1090));
        players.add(new Player("Dale", 982));
        players.add(new Player("Eric", 1018));
      
        //Chloe 가 일등이기 때문에 리스트의 맨 앞으로 나와야하고, Alice 는 꼴등이기 때문에 리스트의 맨 뒤로 보내야합니다.
      
    • Comparable 인터페이스

      • 정렬 대상 클래스에 자바에서 기본적으로 제공하고 있는 Comparable 인터페이스를 implement하고 compareTo()를 @Overrice 한다

        public class Player implements Comparable<Player> {
          // Fields, Getters, Setters 생략
        
          @Override
          public int compareTo(Player o) {
              return o.getScore() - getScore();
          }
        }
        
      • 메서드를 호출하는 객체가 인자로 넘어온 객체보다 작을 경우에는 음수를 리턴하고, 크기가 동일하다면 0, 클 경우에는 양수를 리턴한다

      • 게이머 랭키 페이지의 경우 높은 점수 순으로 내림 차순 정렬을 원하기 때문에, 인자로 넘어온 게이머의 점수에서 메서드를 호출하는 게이머의 점수를 빼면 됩니다.

      • 예를 들어 인자로 넘어온 게이머의 점수가 982이고 compareTo() 메서드를 호출하는 객체의 점수가 1018이라면, compareTo() 메서드는 음수(982-1018)를 리턴하게 되며, 이는 곧 메서드를 호출하는 게미머가 인자로 넘어온 게이머보다 작다는 것을 의미합니다. 다시 말해, 메서드를 호출를 호출하는 메서드가 점수가 더 크지만, 객체 자체 비교에서는 인자로 넘어온 게이머보다 작은 객체가 됩니다.

      • Collections.sort() 오버로딩 일부

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

        Collections.sort(players);
        System.out.println(players); // [Player(name=Chloe, score=1090), Player(name=Eric, score=1018), Player(name=Bob, score=982), Player(name=Dale, score=982), Player(name=Alice, score=899)]
        
      • 이제 Collections.sort() 메서드에는 Comparable 인터페이스를 구현한 Comparable 타입의 Player 객체의 리스트가 인자로 넘어가기 때문에 더 이상 컴파일 에러가 발생하지 않습니다. 정렬 후 게이머 리스트를 출력해보면 원하는 바와 같이 점수가 제일 높은 Chloe 가 리스트의 맨 앞으로 위치하고, 점수가 제일 낮은 Alice 가 리스트의 맨 뒤에 위치하게 됩니다.

    • Comparator 객체 사용

      • 정렬 대상 클래스의 코드를 직접 수정하지 않을 경우

      • 객체에 이미 존재하고 있는 정렬 기준과 다른 정렬 기준을 적용할 경우

      • Arrays.sort() 오버로딩 일부

          public static <T> void sort(T[] a, Comparator<? super T> c) {
              if (c == null) {
                  sort(a);
              } else {
                  if (LegacyMergeSort.userRequested)
                      legacyMergeSort(a, c);
                  else
                      TimSort.sort(a, 0, a.length, c, null, 0, 0);
              }
          }
        
      • Collections.sort() 오버로딩 일부

          public static <T> void sort(List<T> list, Comparator<? super T> c) {
              list.sort(c);
          }
        
      • 정렬 결과

        Comparator<Player> comparator = new Comparator<Player>() {
          @Override
          public int compare(Player a, Player b) {
              return b.getScore() - a.getScore();
          }
        };
        
        Collections.sort(players, comparator);
        System.out.println(players); // [Player(name=Chloe, score=1090), Player(name=Eric, score=1018), Player(name=Bob, score=982), Player(name=Dale, score=982), Player(name=Alice, score=899)]
        
      • 람다 함수로 정렬

        • Comparator 객체는 메서드가 하나 뿐인 함수형 인터페이스를 구현하기 때문에 람다 함수로 대체가 가능합니다.
        Collections.sort(players, (a, b) -> b.getScore() - a.getScore());
        System.out.println(players); // [Player(name=Chloe, score=1090), Player(name=Eric, score=1018), Player(name=Bob, score=982), Player(name=Dale, score=982), Player(name=Alice, score=899)]
        
      • Stream으로 정렬

        • Stream 클래스의 sorted() 메서드도 Comparator 객체를 인자로 받아 정렬을 해줍니다. 스트림을 사용하면 위에서 살펴본 배열과 리스트의 정렬과 달리 기존 객체의 순서를 변경하지 않고, 새롭게 정렬된 객체를 생성하고자 할 때 사용됩니다
        List<Player> sortedPlayers = players.stream()
              .sorted((a, b) -> b.getScore() - a.getScore())
              .collect(Collectors.toList());
        System.out.println(sortedPlayers); // [Player(name=Chloe, score=1090), Player(name=Eric, score=1018), Player(name=Bob, score=982), Player(name=Dale, score=982), Player(name=Alice, score=899)]
        
  • 참고 자료