본문 바로가기
Today I Learned 2024. 6. 11.

(24.06.11)[9주차] HashMap + 사용자 정의 Comparator 사용하기

Custom Comparator에 대해서 전에 다뤘지만, HashMap을 활용하는데 있어서 Generics 의 일치와 사용방법을 더해서 새롭게 정리를 하면서 Collection Framework의 사용을 다시 한번 더 정리하면서 학습!


HashMap + 사용자정의 Comparator 사용하기

  • KODA KATA를 진행하면서 주어진 문제를 살짝 변형해서 학습할 수 있도록 HashMap 구조와 사용자 정의 Comparator를 함께 사용하여 코드를 작성하고 연습하려고 했다.
    • HashMap 의 Key-Value에 관하여 Comparator에서 사용될 수 있을지 의문이 들기도 했고, 처음 코드를 작성했을때, Value를 하나씩 꺼내서 비교하고, 그 Value 에 맞는 키 값을 또 찾아서 반환하는 로직을 다시 학습하면서 수정해서 기록
public class Main {
    public static void main(String[] args) {

        int[] answers = {1, 2, 3, 4, 5};
        int[] firstTester = {1, 2, 3, 4, 5}; //5개
        int[] secondTester = {2, 1, 2, 3, 2, 4, 2, 5}; //8개
        int[] thirdTester = {3, 3, 1, 1, 2, 2, 4, 4, 5, 5}; //10개

        int firstCount = 0;
        int secondCount = 0;
        int thirdCount = 0;

        for (int index = 0; index < answers.length; index++) {
            int answerNumber = answers[index];

            if (firstTester[index % 5] == answerNumber) {
                firstCount++;
            }

            if (secondTester[index % 8] == answerNumber) {
                secondCount++;
            }

            if (thirdTester[index % 10] == answerNumber) {
                thirdCount++;
            }
        }

        HashMap<String, Integer> testerMap = new HashMap<>();
        testerMap.put("firstTester", firstCount);
        testerMap.put("secondTester", secondCount);
        testerMap.put("thirdTester", thirdCount);
        
        ArrayList<Map.Entry<String, Integer>> testerList = new ArrayList<>(testerMap.entrySet());
        
        Comparator<Map.Entry<String, Integer>> compareAnswer = new Comparator<Map.Entry<String, Integer>>() {
            @Override
            public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
                return Integer.compare(o2.getValue(), o1.getValue());
            }
        };

        Collections.sort(testerList, compareAnswer);

        ArrayList<String> orderList = new ArrayList<>();
        for (int index = 0; index < 3; index++) {
            if (testerList.get(index).getValue() != 0) {
                orderList.add(testerList.get(index).getKey());
            }
        }

        System.out.println(orderList);
    }
}
위의 문제는 3명이 일정한 패턴으로 답을 제시한다고 했을 때, answers 배열의 순서대로 3명의 답을 채점을 하고, 고득점 순서대로 리스트를 반환하는 코드

 

HashMap <-> List

        HashMap<String, Integer> testerMap = new HashMap<>();
        testerMap.put("firstTester", firstCount);
        testerMap.put("secondTester", secondCount);
        testerMap.put("thirdTester", thirdCount);
        
        ArrayList<Map.Entry<String, Integer>> testerList = new ArrayList<>(testerMap.entrySet());
  • HashMap은 <> 지네릭스를 통해서 key-value Pair의 각각의 타입을 지정
    • HashMap 에서 Pair은 Entry
  • HashMap의 put() 메서드를 통한 Entry 값 넣기
    • 단, HashMap은 순서보장이 되지 않는 컬렉션이기 때문에 넣은 순서대로 나중에 ArrayList로 바꿔서 객체를 생성했을때, 순서가 잡혀버림
  • ArrayList로 변환
    • HashMap의 모든 Entry를 Set로 반환 -> 배열로 판단 -> ArrayList 객체로 새롭게 지정 가능 
    • ArrayList의 지네릭스는 HashMap의 엔트리의 Key-Value와 같아야 하고, ArrayList<<String,Integer>> 가 아니라 Map.Entry<String, Integer> 로 엔트리 째로 타입을 지정을 해줘야함
    • HashMap의 entrySet() 메서드를 통해서 모든 Entry를 Set로 반환

 

Custom Comparator & HashMap

        Comparator<Map.Entry<String, Integer>> compareAnswer = new Comparator<Map.Entry<String, Integer>>() {
            @Override
            public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
                return Integer.compare(o2.getValue(), o1.getValue());
            }
        };

        Collections.sort(testerList, compareAnswer);
  • Custom Comparator의 타입도 역시 HashMap으로 만들어진 ArrayList 객체의 타입과 일치한 Map.Entry<String, Integer>
  • @Override를 사용해서 compare하는 변수들의 타입들도 역시 Entry 이기 때문에 Map.Entry<String, Integer>
  • return에서 쓰이는 변수들은 무조건 o1 o2  형태가 아니어도 됨
    • 잘못 이해하고 있었던 부분 -> 가공을 할 수 있음
    • return o2.getValue().compareTo(o1.getValue()); 으로 변경 가능
      • Comparable 구현에서 쓰는 방식

Summary

public interface Map.Entry<K,V> {
    K getKey(); // 엔트리의 키를 반환하는 메서드
    V getValue(); // 엔트리의 값(value)를 반환하는 메서드
    V setValue(V value); // 엔트리의 값(value)을 설정하는 메서드
}
  • HashMap을 중심으로 ArrayList 외 컬렉션, Comparator 의 Generics를 사요을 해야할때, Entry 타입을 지정을 해줘야함
    • 간단하게 Map.Entry<(Key 타입),(Value 타입)> 을 사용한, 일종의 Map.Entry 인터페이스의 구현체가 타입이 되는 것