글을 쓰는 이유
코딩 테스트 문제를 풀 때 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