1. Overview
1.概述
Map is a common data type when we need to manage key-value associations. The LinkedHashMap is a popular choice, primarily known for preserving the insertion order. However, in many real-world scenarios, we often need to sort the elements of a LinkedHashMap based on their values rather than keys.
是我们需要管理键值关联时常用的数据类型。LinkedHashMap 是一种流行的选择,主要以保留插入顺序而著称。但是,在许多实际应用场景中,我们经常需要根据 LinkedHashMap 的值而不是键对元素进行排序。
In this tutorial, we’ll explore how to sort a LinkedHashMap by values in Java.
在本教程中,我们将探讨如何在 Java 中按值对 LinkedHashMap 进行排序。
2. Sorting by Value
2.按价值排序
The default behavior of a LinkedHashMap is to maintain the order of elements based on the insertion order. This is useful in cases where we want to keep track of the sequence in which elements were added to the map. However, sorting by values is a different requirement. We might like to arrange the entries in ascending or descending order based on the values associated with the keys.
LinkedHashMap 的默认行为是根据插入顺序保持元素的顺序。这在我们希望跟踪元素被添加到映射中的顺序时非常有用。但是,按值排序则是另一种要求。我们可能希望根据与键相关联的值以升序或降序排列条目。
Next, let’s see an example. Let’s say we have a LinkedHashMap called MY_MAP:
接下来,我们来看一个示例。假设我们有一个名为MY_MAP:的LinkedHashMap。
static LinkedHashMap<String, Integer> MY_MAP = new LinkedHashMap<>();
static {
MY_MAP.put("key a", 4);
MY_MAP.put("key b", 1);
MY_MAP.put("key c", 3);
MY_MAP.put("key d", 2);
MY_MAP.put("key e", 5);
}
As the example above shows, we initialized MY_MAP using a static block. The values in the map are integers. Our goal is to sort the map by the values and get a new LinkedHashMap which is equal to EXPECTED_MY_MAP:
如上例所示,我们使用 static 块初始化了 MY_MAP 。映射中的值是整数。我们的目标是按值对映射进行排序,并得到一个新的 LinkedHashMap ,它等于 EXPECTED_MY_MAP:
static LinkedHashMap<String, Integer> EXPECTED_MY_MAP = new LinkedHashMap<>();
static{
EXPECTED_MY_MAP.put("key b", 1);
EXPECTED_MY_MAP.put("key d", 2);
EXPECTED_MY_MAP.put("key c", 3);
EXPECTED_MY_MAP.put("key a", 4);
EXPECTED_MY_MAP.put("key e", 5);
}
Next, we’ll see several approaches to solving the problem. We’ll use unit test assertions to verify each solution.
接下来,我们将看到几种解决问题的方法。我们将使用单元测试断言来验证每种解决方案。
3. Using the Collections.sort() Method
3.使用 Collections.sort() 方法
First, let’s see how to solve the problem if our Java is older than Java 8.
首先,让我们看看如果我们的 Java 早于 Java 8,该如何解决问题。
LinkedHashMap’s entrySet() provides access to all entries while maintaining their original order.
LinkedHashMap的entrySet()可访问所有条目,同时保持其原始顺序。
We can also leverage the Collections.sort() method, which allows us to sort a collection of objects by a given Comparator.
我们还可以利用 Collections.sort() 方法,该方法允许我们通过给定的 Comparator. 对对象集合进行排序。
Let’s look at the solution first:
我们先来看看解决方案:
List<Map.Entry<String, Integer>> entryList = new ArrayList<>(MY_MAP.entrySet());
Collections.sort(entryList, new Comparator<Map.Entry<String, Integer>>() {
@Override
public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
return o1.getValue().compareTo(o2.getValue());
}
});
LinkedHashMap<String, Integer> result = new LinkedHashMap<>();
for (Map.Entry<String, Integer> e : entryList) {
result.put(e.getKey(), e.getValue());
}
assertEquals(EXPECTED_MY_MAP, result);
Let’s walk through the code quickly to understand how it works.
让我们快速浏览一下代码,了解其工作原理。
First, we wrap entrySet()’s result in a List. Then, we created an anonymous Comparator to sort the entries by their values and pass it to the Collections.sort() method. Finally, we create a new LinkedHashMap object and put the sorted entries into it.
首先,我们将 entrySet() 的结果封装在一个 List 中。然后,我们创建了一个匿名 Comparator 来按值对条目进行排序,并将其传递给 Collections.sort() 方法。最后,我们创建了一个新的 LinkedHashMap 对象,并将排序后的条目放入其中。
4. Using forEachOrdered()
4.使用 forEachOrdered()
Stream API is a significant new feature that Java 8 brought us. It allows us to manipulate collections conveniently. Therefore, if the Java version we work with is 8 or later, we can fill an empty LinkedHashMap with sorted entries from the original map using the Stream API:
Stream API 是 Java 8 为我们带来的一项重要新功能。它允许我们方便地操作集合。因此,如果我们使用的 Java 版本是 8 或更高版本,我们就可以使用 Stream API 将原始映射中排序的条目填充到空的 LinkedHashMap 中:
LinkedHashMap<String, Integer> result = new LinkedHashMap<>();
MY_MAP.entrySet()
.stream()
.sorted(Map.Entry.comparingByValue())
.forEachOrdered(entry -> result.put(entry.getKey(), entry.getValue()));
assertEquals(EXPECTED_MY_MAP, result);
As we can see, using the Stream API, the solution is more fluent and compact.
我们可以看到,使用流应用程序接口(Stream API)后,解决方案更加流畅、紧凑。
It’s worth noting that Map.Entry supports the comparingByValue() method. As its name implies, it returns a Comparator that compares entries by their values.
值得注意的是,Map.Entry 支持 comparingByValue() 方法。顾名思义,该方法返回一个 Comparator 方法,用于按值比较条目。
As the Entry.value in our example is Integer, which is Comparable, we can just call comparingByValue() directly.
由于 Entry.value 在我们的示例中是 Integer,它是 Comparable, 我们可以直接调用 comparingByValue() 。
5. Using collect()
5.使用 collect()
An alternative, more streamlined approach involves leveraging the collect() method to both create the map and accumulate the sorted entries in one shot:
另一种更简洁的方法是利用 collect() 方法一次性创建地图和累积排序条目:
LinkedHashMap<String, Integer> result = MY_MAP.entrySet()
.stream()
.sorted(Map.Entry.comparingByValue())
.collect(LinkedHashMap::new, (map, entry) -> map.put(entry.getKey(), entry.getValue()), Map::putAll);
assertEquals(EXPECTED_MY_MAP, result);
The collect() method is the key to this approach. It takes three parameters:
collect() 方法是这种方法的关键。它需要三个参数:
- Supplier (LinkedHashMap::new) – Provide a new container (LinkedHashMap) to accumulate the results
- Accumulator ((map, entry) -> map.put(entry.getKey(), entry.getValue())) – This function is applied to each element in the stream and adds each entry to the accumulating LinkedHashMap
- Combiner (Map::putAll) – In parallel processing, it combines the containers updated by multiple accumulators. In this case, it’s irrelevant, as the stream is processed sequentially.
Thus, collect() accumulates the sorted entries into a new LinkedHashMap.
因此,collect()会将排序后的条目累加到一个新的 LinkedHashMap. 中。
6. When the Values Are Not Comparable
6.当值无法比较</em
We’ve seen how to sort MY_MAP by value. Since the Integer value is Comparable, when we use Stream API, we can simply call sorted(Map.Entry.comparingByValue()).
我们已经了解了如何按值对 MY_MAP 排序。由于 Integer 值是可比较的,当我们使用流 API 时,我们可以简单地调用 sorted(Map.Entry.comparingByValue())。</em
But, if the value is not Comparable, we need to pass a Comparator to comparingByValue():
但是,如果值不可比较,我们就需要向 comparingByValue() 传递一个 Comparator :
class Player {
private String name;
private Integer score = 0;
public Player(String name, Integer score) {
this.name = name;
this.score = score;
}
// ... hashcode, equals, getters methods are omitted ...
}
As the code shows, the Player class doesn’t implement Comparable. Now, let’s initialize a LinkedHashMap<String, Player>:
正如代码所示,Player类没有实现Comparable。现在,让我们初始化一个 LinkedHashMap<String, Player>:
static LinkedHashMap<String, Player> PLAYERS = new LinkedHashMap<>();
static {
PLAYERS.put("player a", new Player("Eric", 9));
PLAYERS.put("player b", new Player("Kai", 7));
PLAYERS.put("player c", new Player("Amanda", 20));
PLAYERS.put("player d", new Player("Kevin", 4));
}
Let’s say we would like to sort PLAYERS by players’ scores and get a new LinkedHashMap:
比方说,我们想按球员得分对 PLAYERS 排序,并得到一个新的 LinkedHashMap:
static LinkedHashMap<String, Player> EXPECTED_PLAYERS = new LinkedHashMap<>();
static {
EXPECTED_PLAYERS.put("player d", new Player("Kevin", 4));
EXPECTED_PLAYERS.put("player b", new Player("Kai", 7));
EXPECTED_PLAYERS.put("player a", new Player("Eric", 9));
EXPECTED_PLAYERS.put("player c", new Player("Amanda", 20));
}
So next, let’s see how to achieve that:
接下来,让我们看看如何做到这一点:
LinkedHashMap<String, Player> result = PLAYERS.entrySet()
.stream()
.sorted(Map.Entry.comparingByValue(Comparator.comparing(Player::getScore)))
.collect(LinkedHashMap::new, (map, entry) -> map.put(entry.getKey(), entry.getValue()), Map::putAll);
assertEquals(EXPECTED_PLAYERS, result);
In this instance, we utilized Comparator.comparing(Player::getScore) within the comparingByValue() method.
在本例中,我们在 comparingByValue() 方法中使用了 Comparator.comparing(Player::getScore) 方法。
This construct generates a Comparator through an instance method reference, specifically comparing the score field of Player objects.
此构造通过实例方法引用生成 Comparator ,特别是比较 Player 对象的 score 字段。
7. Conclusion
7.结论
In this tutorial, we’ve explored different ways to sort a LinkedHashMap by values. We also addressed sorting implementation in scenarios where the values do not implement the Comparable interface.
在本教程中,我们探讨了按值对 LinkedHashMap 排序的不同方法。我们还讨论了在值未实现 Comparable 接口的情况下的排序实现。
As always, the complete source code for the examples is available over on GitHub.
与往常一样,这些示例的完整源代码可在 GitHub 上获取。