在Java中对HashMap进行排序
1.绪论
在这个快速教程中,我们将学习如何在Java中对HashMap进行排序。
更具体地说,我们将研究如何通过键或值对HashMap条目进行排序,使用。
- TreeMap
- ArrayList和Collections.sort()
- TreeSet
- 使用Stream应用程序接口
- 使用Guava library
2.使用TreeMap的方式
正如我们所知,TreeMap 中的键是使用它们的自然顺序排序的。当我们想按键对键值对进行排序时,这是一个很好的解决方案。所以我们的想法是将所有数据从我们的 HashMap 推送到 TreeMap。
首先,让我们定义一个HashMap,并用一些数据对其进行初始化。
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:。
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中。
TreeMap<String, Employee> sorted = new TreeMap<>(map);
我们也可以使用putAll方法来复制数据。
TreeMap<String, Employee> sorted = new TreeMap<>();
sorted.putAll(map);
就这样了:为了确保我们的Map条目是按关键词排序的,让我们把它们打印出来:
Annie=Employee{id=22, name='Annie'}
George=Employee{id=2, name='George'}
John=Employee{id=8, name='John'}
Mher=Employee{id=1, name='Mher'}
正如我们所看到的,键的排序是按自然顺序进行的。
3.使用ArrayList的方式
当然,我们可以在ArrayList的帮助下对Map的条目进行排序。与之前的方法的关键区别在于,我们在这里不维护Map接口。
3.1.按键排序
让我们把键集加载到一个ArrayList中。
List<String> employeeByKey = new ArrayList<>(map.keySet());
Collections.sort(employeeByKey);
而输出的结果是:
[Annie, George, John, Mher]
3.2.按值排序
现在,如果我们想按id对象的Employee字段对我们的Map值进行排序呢?我们也可以用一个ArrayList来实现。
首先,让我们把这些值复制到列表中去:
List<Employee> employeeById = new ArrayList<>(map.values());
然后,我们对其进行分类:
Collections.sort(employeeById);
请记住,这是因为Employee实现了Comparable接口。否则,我们就需要为我们对Collections.sort的调用定义一个手动比较器。
为了检查结果,我们打印出employeeById。
[Employee{id=1, name='Mher'},
Employee{id=2, name='George'},
Employee{id=8, name='John'},
Employee{id=22, name='Annie'}]
正如我们所看到的,这些对象是按照它们的id字段排序的。
4.使用TreeSet
如果我们不想在我们的排序集合中接受重复的值,有一个很好的解决方案,那就是TreeSet。
首先,让我们在我们的初始Map上添加一些重复的条目:
Employee employee5 = new Employee(1L, "Mher");
map.put(employee5.getName(), employee5);
Employee employee6 = new Employee(22L, "Annie");
map.put(employee6.getName(), employee6);
4.1.按键排序
要按键对Map进行排序:
SortedSet<String> keySet = new TreeSet<>(map.keySet());
让我们打印一下keySet,看看输出结果:
[Annie, George, John, Mher]
现在我们有了Map键的排序,没有了重复的东西。
4.2.按值排序
同样,对于Map值,转换代码看起来是这样的:
SortedSet<Employee> values = new TreeSet<>(map.values());
而结果是:
[Employee{id=1, name='Mher'},
Employee{id=2, name='George'},
Employee{id=8, name='John'},
Employee{id=22, name='Annie'}]
如我们所见,输出中没有重复项。 当我们覆盖equals 和hashCode 时,这适用于自定义对象。
5.使用Lambdas和流
从Java 8开始,我们可以使用Stream API和lambda表达式来对Map进行排序。我们只需要在Map的流管道上调用sorted方法。
5.1.按键排序
要按键排序,我们使用comparingByKey比较器:
map.entrySet()
.stream()
.sorted(Map.Entry.<String, Employee>comparingByKey())
.forEach(System.out::println);
最后的forEach阶段会打印出结果:
Annie=Employee{id=22, name='Annie'}
George=Employee{id=2, name='George'}
John=Employee{id=8, name='John'}
Mher=Employee{id=1, name='Mher'}
默认情况下,排序模式是升序的。
5.2.按值排序
当然,我们也可以按Employee对象进行排序:
map.entrySet()
.stream()
.sorted(Map.Entry.comparingByValue())
.forEach(System.out::println);
正如我们所看到的,上面的代码打印出了一张按Employee对象的id字段排序的Map:
Mher=Employee{id=1, name='Mher'}
George=Employee{id=2, name='George'}
John=Employee{id=8, name='John'}
Annie=Employee{id=22, name='Annie'}
此外,我们还可以将结果收集到一张新的Map中:
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并不能保证迭代order,而LinkedHashMap能做到。
6.使用Guava
最后,一个允许我们对HashMap进行排序的库是Guava。在我们开始之前,看看我们写的关于Guava maps的文章会很有用。
首先,让我们声明一个Ordering,因为我们想通过Employee Id字段来对我们的Map进行排序。
Ordering naturalOrdering = Ordering.natural()
.onResultOf(Functions.forMap(map, null));
现在我们所需要的是使用ImmutableSortedMap来说明结果:
ImmutableSortedMap.copyOf(map, naturalOrdering);
再一次,输出的是一张按id字段排序的Map:
Mher=Employee{id=1, name='Mher'}
George=Employee{id=2, name='George'}
John=Employee{id=8, name='John'}
Annie=Employee{id=22, name='Annie'}
7.摘要
在这篇文章中,我们回顾了按键或值对HashMap进行排序的若干方法。
我们还学习了如何通过实现Comparable 当属性是一个自定义类时做到这一点。
最后,像往常一样,本文中使用的代码可以在GitHub上找到。