Java HashMap 정렬
1. TreeMap 사용
TreeMap의 키는 자연 순서를 사용하여 정렬된다. 이는 키를 기준으로 키-값 쌍을 정렬하려는 경우 좋은 솔루션이다. 따라서 HashMap의 모든 데이터를 TreeMap으로 푸시하는 것이다.
HashMap을 정의 하고 일부 데이터로 초기화한다.
1
2
3
4
5
6
7
8
9
10
Map<String, Employee> map = new HashMap<>();
Employee employee1 = new Employee(1L, "Mher");
map.put(employee1.getName(), employee1);
Employee employee2 = new Employee(22L, "Annie");
map.put(employee2.getName(), employee2);
Employee employee3 = new Employee(8L, "John");
map.put(employee3.getName(), employee3);
Employee employee4 = new Employee(2L, "George");
map.put(employee4.getName(), employee4);
Employee 클래스의 경우 Comparable을 구현했다.
1
2
3
4
5
6
7
8
9
10
11
12
13
public class Employee implements Comparable<Employee> {
private Long id;
private String name;
// constructor, getters, setters
// override equals and hashCode
@Override
public int compareTo(Employee employee) {
return (int)(this.id - employee.getId());
}
}
다음으로 생성자를 사용하여 TreeMap에 항목을 저장한다.
1
TreeMap<String, Employee> sorted = new TreeMap<>(map);
putAll 메서드를 사용하여 데이터를 복사할 수도 있다.
1
2
TreeMap<String, Employee> sorted = new TreeMap<>();
sorted.putAll(map);
맵 항목이 키별로 정렬되었는지 확인하기 위해 출력한다.
1
2
3
4
Annie=Employee{id=22, name='Annie'}
George=Employee{id=2, name='George'}
John=Employee{id=8, name='John'}
Mher=Employee{id=1, name='Mher'}
키는 자연스러운 순서로 정렬된다.
2. ArrayList 사용
ArrayList의 도움으로 맵의 항목을 정렬할 수 있다. 이전 방법과의 주요 차이점은 여기에서 맵 인터페이스를 유지 관리하지 않는다는 것이다.
1) 키로 정렬
키 세트를 ArrayList에 로드한다.
1
2
List<String> employeeByKey = new ArrayList<>(map.keySet());
Collections.sort(employeeByKey);
결과는 다음과 같다.
1
[Annie, George, John, Mher]
2) 값으로 정렬
Employee 개체의 id 필드를 기준으로 맵 값을 정렬하려면 ArrayList를 사용할 수도 있다.
값을 목록에 복사한다.
1
List<Employee> employeeById = new ArrayList<>(map.values());
그런 다음 정렬한다.
1
Collections.sort(employeeById);
Employee가 Comparable 인터페이스를 구현하기 때문에 이것이 작동한다. 그렇지 않으면 Collections.sort
호출을 위한 수동 비교기를 정의해야 한다.
결과를 확인하기 위해 employeeById를 출력한다.
1
2
3
4
[Employee{id=1, name='Mher'},
Employee{id=2, name='George'},
Employee{id=8, name='John'},
Employee{id=22, name='Annie'}]
객체는 id 필드로 정렬된다.
3. TreeSet 사용
정렬된 컬렉션에서 중복 값을 허용하지 않으려면 TreeSet을 사용하는 좋은 솔루션이 있다.
먼저 초기 맵에 일부 중복 항목을 추가한다.
1
2
3
4
Employee employee5 = new Employee(1L, "Mher");
map.put(employee5.getName(), employee5);
Employee employee6 = new Employee(22L, "Annie");
map.put(employee6.getName(), employee6);
1) 키로 정렬
키 항목을 기준으로 맵을 정렬한다.
1
SortedSet<String> keySet = new TreeSet<>(map.keySet());
keySet을 출력한다.
1
[Annie, George, John, Mher]
중복 없이 정렬된 맵 키가 있다.
2) 값으로 정렬
마찬가지로 맵 값의 경우 전환 코드는 다음과 같다.
1
SortedSet<Employee> values = new TreeSet<>(map.values());
결과는 다음과 같다.
1
2
3
4
[Employee{id=1, name='Mher'},
Employee{id=2, name='George'},
Employee{id=8, name='John'},
Employee{id=22, name='Annie'}]
출력에 중복이 없다. 이는 equals 및 hashCode를 재정의할 때 사용자 지정 개체와 함께 작동한다.
4. 람다와 스트림 사용
Java 8부터 Stream API 및 람다 식을 사용하여 맵을 정렬할 수 있다. 맵의 스트림 파이프라인을 통해 정렬된 메서드를 호출하기만 하면 된다.
1) 키로 정렬
키별로 정렬하려면 ComparatorByKey 비교기를 사용한다.
1
2
3
4
map.entrySet()
.stream()
.sorted(Map.Entry.<String, Employee>comparingByKey())
.forEach(System.out::println);
마지막 forEach 단계는 결과를 출력한다.
1
2
3
4
Annie=Employee{id=22, name='Annie'}
George=Employee{id=2, name='George'}
John=Employee{id=8, name='John'}
Mher=Employee{id=1, name='Mher'}
기본적으로 정렬 모드는 오름차순이다.
2) 값으로 정렬
물론 Employee 객체를 기준으로 정렬할 수도 있다.
1
2
3
4
map.entrySet()
.stream()
.sorted(Map.Entry.comparingByValue())
.forEach(System.out::println);
보시다시피 위의 코드는 Employee 객체의 id 필드로 정렬된 맵을 출력한다.
1
2
3
4
Mher=Employee{id=1, name='Mher'}
George=Employee{id=2, name='George'}
John=Employee{id=8, name='John'}
Annie=Employee{id=22, name='Annie'}
또한 결과를 새 맵으로 수집할 수 있다.
1
2
3
4
5
6
7
Map<String, Employee> result = map.entrySet()
.stream()
.sorted(Map.Entry.comparingByValue())
.collect(Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue,
(oldValue, newValue) -> oldValue, LinkedHashMap::new));
결과를 LinkedHashMap에 수집했다. 기본적으로 Collectors.toMap
은 새로운 HashMap을 반환하지만, HashMap은 반복 순서를 보장하지 않지만 LinkedHashMap은 보장한다.
4. Guava 사용
마지막으로 HashMap을 정렬할 수 있는 라이브러리는 Guava이다.
Employee의 Id 필드를 기준으로 지도를 정렬하기 위해 Ordering을 선언한다.
1
2
Ordering naturalOrdering = Ordering.natural()
.onResultOf(Functions.forMap(map, null));
이제 ImmutableSortedMap을 사용하여 결과를 설명하기만 하면 된다.
1
ImmutableSortedMap.copyOf(map, naturalOrdering);
그리고 다시 한번 출력은 id 필드로 정렬된 맵이다.
1
2
3
4
Mher=Employee{id=1, name='Mher'}
George=Employee{id=2, name='George'}
John=Employee{id=8, name='John'}
Annie=Employee{id=22, name='Annie'}