값별로 카드 정렬

글을 쓰는 이유

코딩 테스트 문제를 풀 때 HashMap을 값으로 정렬해야 할 일이 생긴다

세부 사항

정렬을 위해서는 목록 형태의 지도를 얻어야 합니다. 따라서 Map.entrySet()을 사용하여 아래와 같이 Map EntrySet을 목록 형식으로 저장합니다. 메서드를 사용하여 이 EntrySet을 정렬합니다.

Map<String, Integer> map = new HashMap<>();
map.put("a", 3);
map.put("b", 2);
map.put("c", 1);
List<Map.Entry<String, Integer>> entryList = new LinkedList<>(map.entrySet());

Entry의 내장 함수 사용

먼저 Map.Entry에서 ComparisonByValue() 함수를 사용하여 아래와 같이 정렬할 수 있습니다.

Map<String, Integer> map = new HashMap<>();
map.put("a", 3);
map.put("b", 2);
map.put("c", 1);
List<Map.Entry<String, Integer>> entryList = new LinkedList<>(map.entrySet());
entryList.sort(Map.Entry.comparingByValue());
for(Map.Entry<String, Integer> entry : entryList){
    System.out.println("key : " + entry.getKey() + ", value : " + entry.getValue());
}

//key : c, value : 1
//key : b, value : 2
//key : a, value : 3

비교기 사용

또 다른 방법은 아래와 같이 비교기 인터페이스를 사용하여 정렬하는 것입니다.

Map<String, Integer> map = new HashMap<>();
map.put("a", 3);
map.put("b", 2);
map.put("c", 1);
List<Map.Entry<String, Integer>> entryList = new LinkedList<>(map.entrySet());
entryList.sort(new Comparator<Map.Entry<String, Integer>>() {
    @Override
    public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
	return o1.getValue() - o2.getValue();
    }
});
for(Map.Entry<String, Integer> entry : entryList){
    System.out.println("key : " + entry.getKey() + ", value : " + entry.getValue());
}

//key : c, value : 1
//key : b, value : 2
//key : a, value : 3

또한 Comparator를 사용하므로 o1과 o2의 순서를 다음과 같이 변경한다. 내림차순를 기준으로 정렬할 수도 있습니다.

Map<String, Integer> map = new HashMap<>();
map.put("a", 1);
map.put("b", 2);
map.put("c", 3);
List<Map.Entry<String, Integer>> entryList = new LinkedList<>(map.entrySet());
entryList.sort(new Comparator<Map.Entry<String, Integer>>() {
    @Override
    public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
	return o2.getValue() - o1.getValue();
    }
});
for(Map.Entry<String, Integer> entry : entryList){
	System.out.println("key : " + entry.getKey() + ", value : " + entry.getValue());
}

//key : a, value : 3
//key : b, value : 2
//key : c, value : 1

람다 함수 사용

위에서 사용한 비교기는 아래와 같이 람다 함수로도 구현할 수 있습니다. 같은 방식으로 내림차순으로 정렬할 수도 있습니다.

Map<String, Integer> map = new HashMap<>();
map.put("a", 3);
map.put("b", 2);
map.put("c", 1);
List<Map.Entry<String, Integer>> entryList = new LinkedList<>(map.entrySet());
entryList.sort(((o1, o2) -> map.get(o1.getKey()) - map.get(o2.getKey())));
for(Map.Entry<String, Integer> entry : entryList){
    System.out.println("key : " + entry.getKey() + ", value : " + entry.getValue());
}

//key : c, value : 1
//key : b, value : 2
//key : a, value : 3

Entry의 비교함수나 Comparator의 비교함수를 사용하지 않고 오버라이딩하여 사용하는 상황은 클래스를 생성하여 사용할 때이다. 새로 생성된 클래스를 HaspMap의 Value 타입으로 사용할 때 클래스 내부의 멤버 변수를 기준으로 정렬하고 싶다면 이렇게 구현하면 됩니다!

    public static class MyClass{
        private int num;
        MyClass(int num){
            this.num = num;
        }
    }
    
    public static void main(String() args){
        Map<String, MyClass> map = new HashMap<>();
        map.put("a", new MyClass(3));
        map.put("b", new MyClass(2));
        map.put("c", new MyClass(1));
        List<Map.Entry<String, MyClass>> entryList = new LinkedList<>(map.entrySet());
        entryList.sort(((o1, o2) -> o1.getValue().num - o2.getValue().num));
        for(Map.Entry<String, MyClass> entry : entryList){
            System.out.println("key : " + entry.getKey() + ", value : " + entry.getValue().num);
        }
    }
    
//key : c, value : 1
//key : b, value : 2
//key : a, value : 3

(참조)https://velog.io/@cgw0519/Java-HashMap-Value-by-Sorting