一尘不染

Java Hashmap:如何从价值中获取关键?

java

如果我有value "foo",并且HashMap<String> ftw为其ftw.containsValue("foo")返回a true,那么如何获取相应的键?我是否必须遍历哈希图?最好的方法是什么?


阅读 337

收藏
2020-02-27

共2个答案

一尘不染

如果你选择使用Commons Collections库而不是标准Java Collections API,则可以轻松实现此目的。

Collections库中的BidiMap接口是一个双向映射,使你可以将键映射到值(如法线映射),也可以将值映射到键,从而允许你在两个方向上执行查找。getKey()方法支持获取值的键。

需要注意的是,bidi映射不能将多个值映射到键,因此,除非你的数据集在键和值之间具有1:1映射,否则你不能使用bidimaps。

更新资料

如果要依赖Java Collections API,则必须在将值插入到映射中时确保键和值之间的1:1关系。说起来容易做起来难。

一旦可以确保使用,请使用entrySet()方法获取Map中的一组条目(映射)。获得类型为Map.Entry的集合后,请遍历条目,将存储的值与期望值进行比较,并获得对应的key。

更新#2

可以在Google Guava和重构的Commons-Collections库(后者不是Apache项目)中找到对带有泛型的比迪地图的支持。感谢Esko指出Apache Commons Collections中缺少的通用支持。将集合与泛型一起使用可使代码更易于维护。

2020-02-27
一尘不染

如果你的数据结构在键和值之间具有多对一映射,则应遍历条目并选择所有合适的键:

public static <T, E> Set<T> getKeysByValue(Map<T, E> map, E value) {
    Set<T> keys = new HashSet<T>();
    for (Entry<T, E> entry : map.entrySet()) {
        if (Objects.equals(value, entry.getValue())) {
            keys.add(entry.getKey());
        }
    }
    return keys;
}

如果是一对一关系,则可以返回第一个匹配的键:

public static <T, E> T getKeyByValue(Map<T, E> map, E value) {
    for (Entry<T, E> entry : map.entrySet()) {
        if (Objects.equals(value, entry.getValue())) {
            return entry.getKey();
        }
    }
    return null;
}

在Java 8中:

public static <T, E> Set<T> getKeysByValue(Map<T, E> map, E value) {
    return map.entrySet()
              .stream()
              .filter(entry -> Objects.equals(entry.getValue(), value))
              .map(Map.Entry::getKey)
              .collect(Collectors.toSet());

}

此外,对于Guava用户,BiMap可能会有用。例如:

BiMap<Token, Character> tokenToChar = 
    ImmutableBiMap.of(Token.LEFT_BRACKET, '[', Token.LEFT_PARENTHESIS, '(');
Token token = tokenToChar.inverse().get('(');
Character c = tokenToChar.get(token);
2020-02-27