Get the Key for a Value from a Java Map – 从一个Java地图中获取一个值的密钥

最后修改: 2018年 9月 13日

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

 

1. Introduction

1.绪论

In this quick tutorial, we’re going to demonstrate three different approaches for retrieving the key from a map for a given value. We’ll also discuss the positives and negatives of the various solutions.

在这个快速教程中,我们将演示三种不同的方法,以从地图中检索给定值的键。我们还将讨论各种解决方案的正面和负面因素。

To learn more about the Map interface, you can check out this article.

要了解有关Map接口的更多信息,你可以查看这篇文章

2. An Iterative Approach

2.迭代的方法

The Map interface of Java Collections offers a method called entrySet(). It returns all the entries or key-value pairs of the map in a Set.

Java CollectionsMap接口提供了一个名为entrySet()的方法。它在一个Set中返回地图的所有条目或键值对。

The idea is to iterate over this entry-set and return the key for which the value matches the supplied value:

我们的想法是在这个条目集上进行迭代,并返回值与提供的值相匹配的键:

public <K, V> K getKey(Map<K, V> map, V value) {
    for (Entry<K, V> entry : map.entrySet()) {
        if (entry.getValue().equals(value)) {
            return entry.getKey();
        }
    }
    return null;
}

However, there might be a possibility that multiple keys are pointing to the same value.

然而,可能会出现多个键指向同一个值的情况。

In that case, if a matching value is found, we add the key to a Set and continue the loop. In the end, we return the Set containing all the desired keys:

在这种情况下,如果找到一个匹配的值,我们就把这个键添加到一个Set中,然后继续循环。最后,我们返回包含所有所需键的Set

public <K, V> Set<K> getKeys(Map<K, V> map, V value) {
    Set<K> keys = new HashSet<>();
    for (Entry<K, V> entry : map.entrySet()) {
        if (entry.getValue().equals(value)) {
            keys.add(entry.getKey());
        }
    }
    return keys;
}

Although this is a very straight-forward implementation, it compares all the entries even if all matches are found after a few iterations.

尽管这是一个非常直接的实现,它比较了所有的条目,即使在几个迭代之后找到了所有的匹配。

3. A Functional Approach

3.功能性的方法

With the introduction of Lambda Expressions in Java 8, we can do it in a more flexible and readable way. We convert the entry-set to a Stream and supply a lambda to filter only those entries with the given value.

随着Java 8中Lambda表达式的引入,我们可以用一种更灵活、更可读的方式来实现。我们将条目集转换为Stream,并提供一个lambda,只过滤那些具有给定值的条目。

Then we use the map method to return a Stream of the keys from the filtered entries:

然后,我们使用map方法来返回一个Stream,即过滤后的条目的键。

public <K, V> Stream<K> keys(Map<K, V> map, V value) {
    return map
      .entrySet()
      .stream()
      .filter(entry -> value.equals(entry.getValue()))
      .map(Map.Entry::getKey);
}

The advantage of returning a stream is that it can cater to a wide range of client needs. The calling code may require only one key or all the keys pointing to the supplied value. As the evaluation of a stream is lazy, the client can control the number of iteration based on its requirement.

返回流的优势在于它可以满足广泛的客户端需求。调用代码可能只需要一个键或所有指向所提供值的键。由于流的评估是懒惰的,客户端可以根据其要求控制迭代的次数。

Additionally, the client may convert the stream to any collection using an appropriate collector:

此外,客户端可以使用适当的收集器将流转换为任何集合。

Stream<String> keyStream1 = keys(capitalCountryMap, "South Africa");
String capital = keyStream1.findFirst().get();

Stream<String> keyStream2 = keys(capitalCountryMap, "South Africa");
Set<String> capitals = keyStream2.collect(Collectors.toSet());

4. Using Apache Commons Collections

4.使用Apache Commons集合

The above ideas wouldn’t be very helpful if we need to call the functions very frequently for a particular map. It will unnecessarily iterate the set of its keys again and again.

如果我们需要非常频繁地调用某个地图的函数,那么上述想法就没有什么用处了。它将不必要地一次又一次地迭代其键的集合。

In this scenario, maintaining another map of value to the keys would make more sense as it will take constant time to retrieve the key for a value.

在这种情况下,维护另一个值与键的映射会更有意义,因为检索一个值的键需要持续的时间。

The Commons Collections library by Apache provides with such a bi-directional Map called BidiMap. It has a method named getKey() for retrieving a key for a given value:

ApacheCommons Collections库提供了这样一个双向的Map,叫做BidiMap。它有一个名为getKey()的方法,用于检索一个给定值的键。

BidiMap<String, String> capitalCountryMap = new DualHashBidiMap<>();
capitalCountryMap.put("Berlin", "Germany");
capitalCountryMap.put("Cape Town", "South Africa");
String capitalOfGermany = capitalCountryMap.getKey("Germany");

However, BidiMap imposes a 1:1 relationship between its keys and values. If we try to put a key-value pair for which the value already exists in the Map, it removes the old entry. In other words, it updates the key against the value.

然而,BidiMap在其键和值之间施加了1:1的关系。如果我们试图在Map中放入一个键值已经存在的键值对,它会删除旧的条目。换句话说,它根据值来更新键。

Also, it requires a larger amount of memory for keeping the reverse map.

另外,它需要较大的内存来保存反向地图。

More details on how to use a BidiMap are in this tutorial.

关于如何使用BidiMap的更多细节,见本教程

5. Using Google Guava

5.使用Google Guava

We may use another bi-directional Map called BiMap found in Guava developed by Google. This class provides a method named inverse() to get the value-key Map or the reverse Map to fetch the key based on a given value:

我们可以使用另一个双向的Map,叫做BiMap,在Google开发的Guava中发现。这个类提供了一个名为inverse()的方法来获取值-键Map或反向Map来获取基于指定值的键。

HashBiMap<String, String> capitalCountryMap = HashBiMap.create();
capitalCountryMap.put("Berlin", "Germany");
capitalCountryMap.put("Cape Town", "South Africa");
String capitalOfGermany = capitalCountryMap.inverse().get("Germany");

Like BidiMap, BiMap also doesn’t allow multiple keys referring to the same value. If we try to make such an attempt, it throws a java.lang.IllegalArgumentException.

BidiMap一样,BiMap也不允许多个键指向同一个值。如果我们试图进行这样的尝试,它会抛出一个java.lang.IllegalArgumentException

Needless to say, BiMap also uses a significant amount of memory as it has to store the inverse map inside. If you are interested to know more about BiMap, you can check out this tutorial

不用说,BiMap也使用了大量的内存,因为它必须在里面存储逆向地图。如果你有兴趣了解更多关于BiMap的信息,你可以查看这个教程

6. Conclusion

6.结语

In this brief article, we’ve discussed some methods of retrieving a Map’s key given the value. Each approach has its own pros and cons. We should always consider the use-cases and choose the most appropriate one based on the situation.

在这篇简短的文章中,我们讨论了一些检索Map的键给定值的方法。每种方法都有自己的优点和缺点。我们应该始终考虑使用情况,并根据情况选择最合适的方法。

The complete source code for the above tutorial is available over on GitHub.

上述教程的完整源代码可在GitHub上找到