Java有反向查找的HashMap吗?

我的数据是按“键 – 键”格式组织的,而不是“键 – 值”。 这就像一个HashMap,但是我需要在两个方向上进行O(1)查找。 这种types的数据结构是否有名称,并且类似于Java标准库中包含的名称? (或者Apache Commons?)

我可以写我自己的类,基本上使用两个镜像地图,但我宁愿不重新发明轮子(如果这已经存在,但我只是没有寻找合适的期限)。

Java API中没有这样的类。 您需要的Apache Commons类将成为BidiMap的实现之一。

作为一名math家,我将这种结构称为双射。

除了Apache Commons外, Guava还有一个BiMap 。

这是一个简单的类,我用它来完成(我不想有另一个第三方依赖)。 它不提供地图中提供的所有function,但这是一个好的开始。

public class BidirectionalMap<KeyType, ValueType>{ private Map<KeyType, ValueType> keyToValueMap = new ConcurrentHashMap<KeyType, ValueType>(); private Map<ValueType, KeyType> valueToKeyMap = new ConcurrentHashMap<ValueType, KeyType>(); synchronized public void put(KeyType key, ValueType value){ keyToValueMap.put(key, value); valueToKeyMap.put(value, key); } synchronized public ValueType removeByKey(KeyType key){ ValueType removedValue = keyToValueMap.remove(key); valueToKeyMap.remove(removedValue); return removedValue; } synchronized public KeyType removeByValue(ValueType value){ KeyType removedKey = valueToKeyMap.remove(value); keyToValueMap.remove(removedKey); return removedKey; } public boolean containsKey(KeyType key){ return keyToValueMap.containsKey(key); } public boolean containsValue(ValueType value){ return keyToValueMap.containsValue(value); } public KeyType getKey(ValueType value){ return valueToKeyMap.get(value); } public ValueType get(KeyType key){ return keyToValueMap.get(key); } } 

如果没有发生冲突,您可以随时将两个方向添加到相同的HashMap 🙂

在这里我的2美分。

或者你可以使用generics的简单方法。 小菜一碟。

 public static <K,V> Map<V, K> invertMap(Map<K, V> toInvert) { Map<V, K> result = new HashMap<V, K>(); for(K k: toInvert.keySet()){ result.put(toInvert.get(k), k); } return result; } 

当然,你必须有一个具有独特价值的地图。 否则,其中一个将被replace。

这里有一个很老的问题,但是如果别人像我刚刚做的那样有大脑阻塞,并且在这个问题上磕磕绊绊,希望这会有所帮助。

我也在寻找一个双向的HashMap,有时它是最有用的答案中最简单的。

如果你不想重新发明轮子,而不愿意为你的项目添加其他库或项目,那么简单地实现并行数组(或ArrayList,如果你的devise需要的话)。

 SomeType[] keys1 = new SomeType[NUM_PAIRS]; OtherType[] keys2 = new OtherType[NUM_PAIRS]; 

只要知道两个键中的一个键的索引,就可以轻松地请求其他键。 所以你的查找方法可能看起来像这样:

 SomeType getKey1(OtherType ot); SomeType getKey1ByIndex(int key2Idx); OtherType getKey2(SomeType st); OtherType getKey2ByIndex(int key2Idx); 

这是假设你正在使用正确的面向对象的结构,只有方法正在修改这些数组/ ArrayLists,这将是非常简单的,以保持他们的平行。 ArrayList更简单,因为如果数组的大小发生改变,就不需要重新编译,只要一起添加/删除即可。

受到GETAH的回答的启发,我决定自己写一些类似的改进:

  • 该类正在实现Map<K,V> -Interface
  • 这个双向性是真正的保证,通过一个put (至less我希望在此保证)

用法与普通映射类似,以获得映射调用getReverseView()的反向视图。 内容不被复制,只返回一个视图。

我不确定这是否完全是傻瓜式的(实际上可能不是),所以如果您发现任何缺陷,请随时发表评论,我会更新答案。

 public class BidirectionalMap<Key, Value> implements Map<Key, Value> { private final Map<Key, Value> map; private final Map<Value, Key> revMap; public BidirectionalMap() { this(16, 0.75f); } public BidirectionalMap(int initialCapacity) { this(initialCapacity, 0.75f); } public BidirectionalMap(int initialCapacity, float loadFactor) { this.map = new HashMap<>(initialCapacity, loadFactor); this.revMap = new HashMap<>(initialCapacity, loadFactor); } private BidirectionalMap(Map<Key, Value> map, Map<Value, Key> reverseMap) { this.map = map; this.revMap = reverseMap; } @Override public void clear() { map.clear(); revMap.clear(); } @Override public boolean containsKey(Object key) { return map.containsKey(key); } @Override public boolean containsValue(Object value) { return revMap.containsKey(value); } @Override public Set<java.util.Map.Entry<Key, Value>> entrySet() { return Collections.unmodifiableSet(map.entrySet()); } @Override public boolean isEmpty() { return map.isEmpty(); } @Override public Set<Key> keySet() { return Collections.unmodifiableSet(map.keySet()); } @Override public void putAll(Map<? extends Key, ? extends Value> m) { m.entrySet().forEach(e -> put(e.getKey(), e.getValue())); } @Override public int size() { return map.size(); } @Override public Collection<Value> values() { return Collections.unmodifiableCollection(map.values()); } @Override public Value get(Object key) { return map.get(key); } @Override public Value put(Key key, Value value) { Value v = remove(key); getReverseView().remove(value); map.put(key, value); revMap.put(value, key); return v; } public Map<Value, Key> getReverseView() { return new BidirectionalMap<>(revMap, map); } @Override public Value remove(Object key) { if (containsKey(key)) { Value v = map.remove(key); revMap.remove(v); return v; } else { return null; } } }