在Java中对HashMap进行排序

评论 0 浏览 0 2018-09-24

1.绪论

在这个快速教程中,我们将学习如何在Java中HashMap进行排序

更具体地说,我们将研究如何通过键或值对HashMap条目进行排序,使用。

  • TreeMap
  • ArrayListCollections.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'}]

如我们所见,输出中没有重复项。 当我们覆盖equalshashCode 时,这适用于自定义对象。

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并不能保证迭代orderLinkedHashMap能做到。

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上找到。

最后更新2023-03-11
0 个评论
标签