【问题标题】:Java Hashmap: How to get key from value?Java Hashmap:如何从值中获取键?
【发布时间】:2010-11-25 21:49:33
【问题描述】:

如果我有值"foo",以及ftw.containsValue("foo") 返回trueHashMap<String> ftw,我怎样才能得到对应的密钥?我必须遍历哈希图吗?最好的方法是什么?

【问题讨论】:

  • 请注意,没有一个对应的键 - 很可能有多个键映射到同一个值。

标签: java hashmap


【解决方案1】:
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;

public class ValueKeysMap<K, V> extends HashMap <K,V>{
    HashMap<V, Set<K>> ValueKeysMap = new HashMap<V, Set<K>>();

    @Override
    public boolean containsValue(Object value) {
        return ValueKeysMap.containsKey(value);
    }

    @Override
    public V put(K key, V value) {
        if (containsValue(value)) {
            Set<K> keys = ValueKeysMap.get(value);
            keys.add(key);
        } else {
            Set<K> keys = new HashSet<K>();
            keys.add(key);
            ValueKeysMap.put(value, keys);
        }
        return super.put(key, value);
    }

    @Override
    public V remove(Object key) {
        V value = super.remove(key);
        Set<K> keys = ValueKeysMap.get(value);
        keys.remove(key);
        if(keys.size() == 0) {
           ValueKeysMap.remove(value);
        }
        return value;
    }

    public Set<K> getKeys4ThisValue(V value){
        Set<K> keys = ValueKeysMap.get(value);
        return keys;
    }

    public boolean valueContainsThisKey(K key, V value){
        if (containsValue(value)) {
            Set<K> keys = ValueKeysMap.get(value);
            return keys.contains(key);
        }
        return false;
    }

    /*
     * Take care of argument constructor and other api's like putAll
     */
}

【讨论】:

    【解决方案2】:
    Iterator<Map.Entry<String,String>> iterator = map.entrySet().iterator();
    while (iterator.hasNext()) {
        Map.Entry<String,String> entry = iterator.next();
        if (entry.getValue().equals(value_you_look_for)) {
            String key_you_look_for = entry.getKey();
    }
    } 
    

    【讨论】:

      【解决方案3】:

      在java8中

      map.entrySet().stream().filter(entry -> entry.getValue().equals(value))
          .forEach(entry -> System.out.println(entry.getKey()));
      

      【讨论】:

        【解决方案4】:
        public static class SmartHashMap <T1 extends Object, T2 extends Object> {
            public HashMap<T1, T2> keyValue;
            public HashMap<T2, T1> valueKey;
        
            public SmartHashMap(){
                this.keyValue = new HashMap<T1, T2>();
                this.valueKey = new HashMap<T2, T1>();
            }
        
            public void add(T1 key, T2 value){
                this.keyValue.put(key, value);
                this.valueKey.put(value, key);
            }
        
            public T2 getValue(T1 key){
                return this.keyValue.get(key);
            }
        
            public T1 getKey(T2 value){
                return this.valueKey.get(value);
            }
        
        }
        

        【讨论】:

        • 我认为这个答案可以通过添加解释来改进。
        • -1。我用String 作为键和值对其进行了测试。当我调用map.add("1", "2"); map.add("1","3"); 时,我可以调用map.getKey("2"); 并检索"1",即使"1""3" 的键。
        • @Jonathan 这个类背后的想法是保留另一个具有反向映射的 HashMap,以便除了从键中检索值之外,您还可以从值中检索键。 T1 和 T2 课程有点混乱;也许从字面上将它们命名为 Key & Value?尽管我希望能够接收多个值或多个键作为回报,具体取决于数据和您想要的内容。谨慎使用
        • @theknightwhosaysni "1" 不再是 "2" 的关键。这也是您问题的答案,调用getValue("1") 将返回3
        • 抱歉 jlordo,我对标准 Hashmap 行为有误:您是正确的,为键添加新值应该替换旧值
        【解决方案5】:

        您可以使用以下代码使用值获取密钥..

        ArrayList valuesList = new ArrayList();
        Set keySet = initalMap.keySet();
        ArrayList keyList = new ArrayList(keySet);
        
        for(int i = 0 ; i < keyList.size() ; i++ ) {
            valuesList.add(initalMap.get(keyList.get(i)));
        }
        
        Collections.sort(valuesList);
        Map finalMap = new TreeMap();
        for(int i = 0 ; i < valuesList.size() ; i++ ) {
            String value = (String) valuesList.get(i);
        
            for( int j = 0 ; j < keyList.size() ; j++ ) {
                if(initalMap.get(keyList.get(j)).equals(value)) {
                    finalMap.put(keyList.get(j),value);
                }   
            }
        }
        System.out.println("fianl map ---------------------->  " + finalMap);
        

        【讨论】:

          【解决方案6】:

          恐怕您只需要迭代您的地图。我能想到的最短的:

          Iterator<Map.Entry<String,String>> iter = map.entrySet().iterator();
          while (iter.hasNext()) {
              Map.Entry<String,String> entry = iter.next();
              if (entry.getValue().equals(value_you_look_for)) {
                  String key_you_look_for = entry.getKey();
              }
          }
          

          【讨论】:

            【解决方案7】:

            是的,您必须遍历哈希图,除非您按照这些不同答案的建议来实现某些东西。与其摆弄 entrySet,我只需获取 keySet(),迭代该集合,并保留为您提供匹配值的(第一个)键。如果您需要与该值匹配的所有键,显然您必须完成所有操作。

            正如 Jonas 建议的那样,这可能已经是 containsValue 方法正在做的事情,因此您可以完全跳过该测试,并且每次都进行迭代(或者编译器可能已经消除了冗余,谁知道呢) .

            此外,相对于其他答案,如果您的反向地图看起来像

            Map<Value, Set<Key>>
            

            如果您需要该功能(将它们放在一边),您可以处理非唯一键-> 值映射。这可以很好地融入人们在这里使用两张地图提出的任何解决方案中。

            【讨论】:

              【解决方案8】:

              如果您在自己的代码中构建地图,请尝试将地图中的键和值放在一起:

              public class KeyValue {
                  public Object key;
                  public Object value;
                  public KeyValue(Object key, Object value) { ... }
              }
              
              map.put(key, new KeyValue(key, value));
              

              那么当你有一个值时,你也有这个键。

              【讨论】:

              • 聪明,但如果有 2 个或更多 KeyValue 对象包含相同的值怎么办?应该选择哪个键?
              • @Vineet,我不明白这种方法如何解决 OP 的问题。 “那么当你有一个价值时,你也有钥匙。”是什么意思?
              【解决方案9】:

              没有明确的答案,因为多个键可以映射到同一个值。如果您使用自己的代码强制执行唯一性,最好的解决方案是创建一个使用两个 Hashmap 来跟踪双向映射的类。

              【讨论】:

                猜你喜欢
                • 2016-03-08
                • 2013-04-21
                • 1970-01-01
                • 2017-08-10
                • 1970-01-01
                • 1970-01-01
                • 2014-09-21
                • 1970-01-01
                相关资源
                最近更新 更多