如果我有value "foo",并且HashMap<String> ftw为其ftw.containsValue("foo")返回a true,那么如何获取相应的键?我是否必须遍历哈希图?最好的方法是什么?
value "foo"
HashMap<String> ftw
ftw.containsValue("foo")
true
如果你选择使用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中缺少的通用支持。将集合与泛型一起使用可使代码更易于维护。
如果你的数据结构在键和值之间具有多对一映射,则应遍历条目并选择所有合适的键:
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);