Sort a HashMap in Java – 在Java中对HashMap进行排序

最后修改: 2018年 9月 24日

中文/混合/英文(键盘快捷键:t)

1. Introduction

1.介绍

In this quick tutorial, we’ll learn how to sort a HashMap in Java.

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

More specifically, we’ll look at sorting HashMap entries by their key or value using:

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

  • TreeMap
  • ArrayList and Collections.sort()
  • TreeSet
  • Using the Stream API
  • Using the Guava library

2. Using a TreeMap

2.使用TreeMap

As we know, keys in TreeMap are sorted using their natural order. This is a good solution when we want to sort the key-value pairs by their key. So the idea is to push all the data from our HashMap into the TreeMap.

正如我们所知,TreeMap中的键是使用其自然顺序排序的。当我们想按键值对排序时,这是一个很好的解决方案。因此,我们的想法是将我们的HashMap中的所有数据推送到TreeMap

To start, let’s define a HashMap and initialize it with some data:

首先,让我们定义一个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);

For the Employee class, note that we implemented Comparable:

对于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());
    }
}

Next, we store the entries in the TreeMap by using its constructor:

接下来,我们通过使用其构造函数将条目存储在TreeMap中。

TreeMap<String, Employee> sorted = new TreeMap<>(map);

We can also use the putAll method to copy the data:

我们也可以使用putAll方法来复制数据。

TreeMap<String, Employee> sorted = new TreeMap<>();
sorted.putAll(map);

And that’s it! To make sure our map entries are sorted by key, let’s print them out:

就这样了!为了确保我们的地图条目是按关键词排序的,让我们把它们打印出来。

Annie=Employee{id=22, name='Annie'}
George=Employee{id=2, name='George'}
John=Employee{id=8, name='John'}
Mher=Employee{id=1, name='Mher'}

As we can see, the keys are sorted in natural order.

正如我们所看到的,这些键是按自然顺序排序的。

3. Using ArrayList

3.使用ArrayList

Of course, we can sort the entries of the map with the help of ArrayList. The key difference from the previous method is that we don’t maintain the Map interface here.

当然,我们可以在ArrayList的帮助下对地图的条目进行排序。与前一个方法的关键区别是,我们在这里不维护Map接口

3.1. Sort by Key

3.1.按键排序

Let’s load the key set into an ArrayList:

让我们把密钥集加载到一个ArrayList中。

List<String> employeeByKey = new ArrayList<>(map.keySet());
Collections.sort(employeeByKey);

And the output is:

而输出是。

[Annie, George, John, Mher]

3.2. Sort by Value

3.2.按价值排序

Now, what if we want to sort our map values by the id field of the Employee object? We can use an ArrayList for that, too.

现在,如果我们想按Employee对象的id字段对我们的map值进行排序,该怎么办?我们也可以使用一个ArrayList来实现。

First, let’s copy the values into the list:

首先,让我们把这些值复制到列表中。

List<Employee> employeeById = new ArrayList<>(map.values());

Then we sort it:

然后我们进行分类。

Collections.sort(employeeById);

Remember that this works because Employee implements the Comparable interface. Otherwise, we’d need to define a manual comparator for our call to Collections.sort.

请记住,这是因为Employee实现了Comparable接口。否则,我们就需要为我们对Collections.sort的调用定义一个手动比较器。

To check the results, we print the employeeById:

为了检查结果,我们打印employeeById

[Employee{id=1, name='Mher'}, 
Employee{id=2, name='George'}, 
Employee{id=8, name='John'}, 
Employee{id=22, name='Annie'}]

As we can see, the objects are sorted by their id field.

正如我们所看到的,这些对象是按其id字段排序的。

4. Using a TreeSet 

4.使用TreeSet

If we don’t want to accept duplicate values in our sorted collection, there’s a nice solution with TreeSet.

如果我们不想在我们的排序集合中接受重复的值,有一个很好的解决方案:TreeSet.

First, let’s add some duplicate entries to our initial 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. Sort by Key

4.1.按键排序

To sort the map by its key entries:

要按关键条目对地图进行排序。

SortedSet<String> keySet = new TreeSet<>(map.keySet());

Let’s print the keySet and see the output:

让我们打印一下keySet,看看输出。

[Annie, George, John, Mher]

Now we have the map keys sorted without the duplicates.

现在我们有了地图键的排序,没有重复的。

4.2. Sort by Value

4.2.按价值排序

Likewise, for the map values, the conversion code looks like:

同样地,对于地图值,转换代码看起来像。

SortedSet<Employee> values = new TreeSet<>(map.values());

And the results are:

而结果是。

[Employee{id=1, name='Mher'}, 
Employee{id=2, name='George'}, 
Employee{id=8, name='John'}, 
Employee{id=22, name='Annie'}]

As we can see, there are no duplicates in the output. This works with custom objects when we override equals and hashCode.

我们可以看到,输出中没有重复的内容。当我们覆盖equalshashCode.时,这对自定义对象有效。

5. Using Lambdas and Streams

5.使用Lambdas和流

Since Java 8, we can use the Stream API and lambda expressions to sort the map. All we need is to call the sorted method over the map’s stream pipeline.

从Java 8开始,我们可以使用Stream API和lambda表达式来对map进行排序。我们只需要在地图的stream 管道上调用sorted方法。

5.1. Sort by Key

5.1.按键排序

To sort by key, we use the comparingByKey comparator:

要按键排序,我们使用comparingByKey比较器。

map.entrySet()
  .stream()
  .sorted(Map.Entry.<String, Employee>comparingByKey())
  .forEach(System.out::println);

The final forEach stage prints out the results:

最后的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'}

By default, the sorting mode is ascending.

默认情况下,排序模式为升序。

5.2. Sort by Value

5.2.按价值排序

Of course, we can sort by the Employee objects as well:

当然,我们也可以按雇员对象排序。

map.entrySet()
  .stream()
  .sorted(Map.Entry.comparingByValue())
  .forEach(System.out::println);

As we can see, the code above prints out a map sorted by the id fields of the Employee objects:

我们可以看到,上面的代码打印出了一张按id字段排序的Employee对象的地图。

Mher=Employee{id=1, name='Mher'}
George=Employee{id=2, name='George'}
John=Employee{id=8, name='John'}
Annie=Employee{id=22, name='Annie'}

Additionally, we can collect the results into a new 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));

Note that we collected our results into a LinkedHashMap. By default, Collectors.toMap returns a new HashMap, but as we know, HashMap doesn’t guarantee iteration order, while LinkedHashMap does.

注意,我们将我们的结果收集到了一个LinkedHashMap中。默认情况下,Collectors.toMap会返回一个新的HashMap,但是正如我们所知,HashMap并不能保证迭代的顺序,而LinkedHashMap可以。

6. Using Guava

6.使用番石榴

Lastly, a library that allows us to sort the HashMap is Guava. Before we begin, it’ll be useful to check our write-up about maps in Guava.

最后,一个允许我们对HashMap进行排序的库是Guava。在我们开始之前,看看我们关于Guava中的地图的文章会很有用。

First, let’s declare an Ordering, as we want to sort our map by the Employee’s Id field:

首先,让我们声明一个Ordering,因为我们想通过Employee的 Id字段来对我们的地图进行排序。

Ordering naturalOrdering = Ordering.natural()
  .onResultOf(Functions.forMap(map, null));

Now all we need is to use ImmutableSortedMap to illustrate the results:

现在我们所需要的是使用ImmutableSortedMap来说明结果。

ImmutableSortedMap.copyOf(map, naturalOrdering);

And once again, the output is a map ordered by the id field:

再一次,输出是一张按id字段排序的地图。

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. Summary

7.总结

In this article, we reviewed a number of ways to sort a HashMap by key or value.

在这篇文章中,我们回顾了按键或值对HashMap进行排序的若干方法。

We also learned how to do this by implementing Comparable when the attribute is a custom class.

我们还学习了如何通过实现Comparable 当属性是一个自定义类时做到这一点。

Finally, as always, the code used in this article can be found over on GitHub.

最后,像往常一样,本文中所使用的代码可以在GitHub上找到