首页 文章

Java Hashmap:如何从值获取密钥?

提问于
浏览
385

如果我有 "foo" 的值, ftw.containsValue("foo") 返回 trueHashMap<String> ftw ,我该如何获得相应的密钥?我是否必须遍历hashmap?最好的方法是什么?

30 回答

  • 3

    要查找映射到该值的所有键,请使用 map.entrySet() 遍历散列映射中的所有对 .

  • 1

    听起来最好的方法是使用 map.entrySet() 迭代条目,因为 map.containsValue() 可能会这样做 .

  • 18

    使用薄包装:HMap

    import java.util.Collections;
    import java.util.HashMap;
    import java.util.Map;
    
    public class HMap<K, V> {
    
       private final Map<K, Map<K, V>> map;
    
       public HMap() {
          map = new HashMap<K, Map<K, V>>();
       }
    
       public HMap(final int initialCapacity) {
          map = new HashMap<K, Map<K, V>>(initialCapacity);
       }
    
       public boolean containsKey(final Object key) {
          return map.containsKey(key);
       }
    
       public V get(final Object key) {
          final Map<K, V> entry = map.get(key);
          if (entry != null)
             return entry.values().iterator().next();
          return null;
       }
    
       public K getKey(final Object key) {
          final Map<K, V> entry = map.get(key);
          if (entry != null)
             return entry.keySet().iterator().next();
          return null;
       }
    
       public V put(final K key, final V value) {
          final Map<K, V> entry = map
                .put(key, Collections.singletonMap(key, value));
          if (entry != null)
             return entry.values().iterator().next();
          return null;
       }
    }
    
  • 0

    值得注意的是,自从这个问题以来,Apache Collections支持Generic BidiMaps . 因此,在这一点上,一些最高投票的答案不再准确 .

    对于也支持重复值的序列化BidiMap(1对多场景)也要考虑MapDB.org .

  • 564

    您可以使用以下内容:

    public class HashmapKeyExist {
        public static void main(String[] args) {
            HashMap<String, String> hmap = new HashMap<String, String>();
            hmap.put("1", "Bala");
            hmap.put("2", "Test");
    
            Boolean cantain = hmap.containsValue("Bala");
            if(hmap.containsKey("2") && hmap.containsValue("Test"))
            {
                System.out.println("Yes");
            }
            if(cantain == true)
            {
                System.out.println("Yes"); 
            }
    
            Set setkeys = hmap.keySet();
            Iterator it = setkeys.iterator();
    
            while(it.hasNext())
            {
                String key = (String) it.next();
                if (hmap.get(key).equals("Bala"))
                {
                    System.out.println(key);
                }
            }
        }
    }
    
  • 7

    我认为你的选择是

    • 使用为此构建的 Map 实现,例如来自google集合的BiMap . 请注意,Google集合BiMap需要无关的值以及键,但它可以在两个方向上提供高性能的性能

    • 手动维护两个映射 - 一个用于键 - >值,另一个映射用于值 - >键

    • 遍历 entrySet() 并找到与该值匹配的键 . 这是最慢的方法,因为它需要遍历整个集合,而其他两种方法不需要这样 .

  • 0

    我认为这是最佳解决方案,原始地址:Java2s

    import java.util.HashMap;
        import java.util.Map;
    
            public class Main {
    
              public static void main(String[] argv) {
                Map<String, String> map = new HashMap<String, String>();
                map.put("1","one");
                map.put("2","two");
                map.put("3","three");
                map.put("4","four");
    
                System.out.println(getKeyFromValue(map,"three"));
              }
    
    
    // hm is the map you are trying to get value from it
              public static Object getKeyFromValue(Map hm, Object value) {
                for (Object o : hm.keySet()) {
                  if (hm.get(o).equals(value)) {
                    return o;
                  }
                }
                return null;
              }
            }
    

    一个简单的用法:如果你把所有数据放在hasMap中并且你有item =“Automobile”,那么你在hashMap中看它的关键 . 这是很好的解决方案 .

    getKeyFromValue(hashMap, item);
    System.out.println("getKeyFromValue(hashMap, item): "+getKeyFromValue(hashMap, item));
    
  • 1

    我认为 keySet() 可能很好找到映射到该值的键,并且具有比 entrySet() 更好的编码风格 .

    例如:

    假设您有一个HashMap映射,ArrayList res, value ,您希望找到 all the key 映射,然后将密钥存储到res .

    您可以在下面编写代码:

    for (int key : map.keySet()) {
            if (map.get(key) == value) {
                res.add(key);
            }
        }
    

    而不是使用下面的entrySet():

    for (Map.Entry s : map.entrySet()) {
            if ((int)s.getValue() == value) {
                res.add((int)s.getKey());
            }
        }
    

    希望能帮助到你 :)

  • 6

    您可以将键,值对及其反转插入到 Map 结构中

    map.put("theKey", "theValue");
    map.put("theValue", "theKey");
    

    然后使用map.get(“theValue”)将返回“theKey” .

    这是一种快速而肮脏的方式,我制作了恒定的 Map ,这只适用于少数几个数据集:

    • 仅包含1对1对

    • 一组值与键组不相交(1-> 2,2-> 3打破它)

  • 1

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

  • 11

    是的,你必须遍历hashmap,除非你按照这些不同的答案建议的方式实现某些东西 . 我只是获取keySet(),迭代该集合,并保留(第一个)键,以获得匹配值,而不是摆弄entrySet . 如果您需要所有与该值匹配的键,显然您必须完成所有操作 .

    正如Jonas所说,这可能已经是containsValue方法正在做的事情,所以你可能只是一起跳过那个测试,并且每次只进行迭代(或者编译器已经消除了冗余,谁知道) .

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

    Map<Value, Set<Key>>
    

    如果你需要这种能力(将它们放在一边),你可以处理非唯一的key->值映射 . 这将很好地融入人们在这里使用两张 Map 建议的任何解决方案 .

  • 2
    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
    public static String getKey(Map<String, Integer> mapref, String value) {
        String key = "";
        for (Map.Entry<String, Integer> map : mapref.entrySet()) {
            if (map.getValue().toString().equals(value)) {
                key = map.getKey();
            }
        }
        return key;
    }
    
  • 11

    我担心你只需要迭代你的 Map . 最短的我可以想出:

    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();
        }
    }
    
  • 5
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.List;
    import java.util.Set;
    
    public class M{
    public static void main(String[] args) {
    
            HashMap<String, List<String>> resultHashMap = new HashMap<String, List<String>>();
    
            Set<String> newKeyList = resultHashMap.keySet();
    
    
            for (Iterator<String> iterator = originalHashMap.keySet().iterator(); iterator.hasNext();) {
                String hashKey = (String) iterator.next();
    
                if (!newKeyList.contains(originalHashMap.get(hashKey))) {
                    List<String> loArrayList = new ArrayList<String>();
                    loArrayList.add(hashKey);
                    resultHashMap.put(originalHashMap.get(hashKey), loArrayList);
                } else {
                    List<String> loArrayList = resultHashMap.get(originalHashMap
                            .get(hashKey));
                    loArrayList.add(hashKey);
                    resultHashMap.put(originalHashMap.get(hashKey), loArrayList);
                }
            }
    
            System.out.println("Original HashMap : " + originalHashMap);
            System.out.println("Result HashMap : " + resultHashMap);
        }
    }
    
  • 6

    虽然这并没有直接回答这个问题,但它是相关的 .

    这样您就不需要继续创建/迭代了 . 只需创建一次反向 Map 即可获得所需内容 .

    /**
     * Both key and value types must define equals() and hashCode() for this to work.
     * This takes into account that all keys are unique but all values may not be.
     *
     * @param map
     * @param <K>
     * @param <V>
     * @return
     */
    public static <K, V> Map<V, List<K>> reverseMap(Map<K,V> map) {
        if(map == null) return null;
    
        Map<V, List<K>> reverseMap = new ArrayMap<>();
    
        for(Map.Entry<K,V> entry : map.entrySet()) {
            appendValueToMapList(reverseMap, entry.getValue(), entry.getKey());
        }
    
        return reverseMap;
    }
    
    
    /**
     * Takes into account that the list may already have values.
     * 
     * @param map
     * @param key
     * @param value
     * @param <K>
     * @param <V>
     * @return
     */
    public static <K, V> Map<K, List<V>> appendValueToMapList(Map<K, List<V>> map, K key, V value) {
        if(map == null || key == null || value == null) return map;
    
        List<V> list = map.get(key);
    
        if(list == null) {
            List<V> newList = new ArrayList<>();
            newList.add(value);
            map.put(key, newList);
        }
        else {
            list.add(value);
        }
    
        return map;
    }
    
  • 0

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

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

    但有一点需要注意,比迪映射不能将多个值映射到键,因此除非您的数据集在键和值之间具有1:1的映射,否则您无法使用bidimaps .

    Update

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

    一旦确定,请使用entrySet() method获取Map中的条目集(映射) . 获得类型为Map.Entry的集合后,迭代条目,将stored value与预期进行比较,并获得corresponding key .

    Update #2

    可以在Google Guava和重构的Commons-Collections库(后者不是Apache项目)中找到对带有泛型的双向 Map 的支持 . 感谢Esko指出Apache Commons Collections中缺少的通用支持 . 使用带有泛型的集合可以使代码更易于维护 .

  • 1
    • 如果您想从值获取密钥,最好使用bidimap(双向映射),您可以在O(1)时间内从值获取密钥 .

    但是,这样做的缺点是你只能使用唯一的键集和值集 .

    • 在java中有一个名为 Table 的数据结构,它只是 Map 的 Map

    Table< A, B , C > == map < A , map < B, C > >

    在这里你可以通过查询 T.row(a); 获得 map<B,C> ,你也可以通过查询 T.column(b); 获得 map<A,C>

    在您的特殊情况下,插入C作为常量 .

    所以,它像<a1,b1,1> <a2,b2,1>,...

    所以,如果你发现通过T.row(a1)--->返回 - > get keyset的 Map ,这个返回的 Map .

    如果需要找到键值,则T.column(b2) - >返回mapof - >获取返回 Map 的键集 .

    优于先前案例的优势:

    • 可以使用多个值 .

    • 使用大型数据集时效率更高 .

  • 8

    我的2美分 . 您可以获取数组中的键,然后遍历数组 . 如果 Map 非常大,这将影响此代码块的性能,在这种情况下,您首先获取数组中的键,这可能会消耗一些时间然后您正在循环 . 否则对于较小的 Map 应该没问题 .

    String[] keys =  yourMap.keySet().toArray(new String[0]);
    
    for(int i = 0 ; i < keys.length ; i++){
        //This is your key    
        String key = keys[i];
    
        //This is your value
        yourMap.get(key)            
    }
    
  • 6

    在java8中

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

    使用Java 8:

    ftw.forEach((key, value) -> {
        if (value=="foo") {
            System.out.print(key);
        }
    });
    
  • 1

    对于针对API <19的Android开发,Vitalii Fedorenko一对一关系解决方案不起作用,因为 Objects.equals isn 't implemented. Here'是一个简单的替代方案:

    public <K, V> K getKeyByValue(Map<K, V> map, V value) {
        for (Map.Entry<K, V> entry : map.entrySet()) {
                if (value.equals(entry.getValue())) {
                return entry.getKey();
            }
        }
        return null;
    }
    
  • 5
    for(int key: hm.keySet()) {
        if(hm.get(key).equals(value)) {
            System.out.println(key); 
        }
    }
    
  • 11

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

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

    然后当你有一个值时,你也有了钥匙 .

  • 0

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

    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);
    
  • 197
    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);
        }
    
    }
    
  • 17

    使用您自己的实现装饰 Map

    class MyMap<K,V> extends HashMap<K, V>{
    
        Map<V,K> reverseMap = new HashMap<V,K>();
    
        @Override
        public V put(K key, V value) {
            // TODO Auto-generated method stub
            reverseMap.put(value, key);
            return super.put(key, value);
        }
    
        public K getKey(V value){
            return reverseMap.get(value);
        }
    }
    
  • 2
    /**
     * This method gets the Key for the given Value
     * @param paramName
     * @return
     */
    private String getKeyForValueFromMap(String paramName) {
        String keyForValue = null;
        if(paramName!=null)) {
            Set<Entry<String,String>> entrySet = myMap().entrySet();
            if(entrySet!=null && entrySet.size>0) {
                for(Entry<String,String> entry : entrySet) {
                    if(entry!=null && paramName.equalsIgnoreCase(entry.getValue())) {
                        keyForValue = entry.getKey();
                    }
                }
            }
        }
        return keyForValue;
    }
    
  • 1
    public class NewClass1 {
    
        public static void main(String[] args) {
           Map<Integer, String> testMap = new HashMap<Integer, String>();
            testMap.put(10, "a");
            testMap.put(20, "b");
            testMap.put(30, "c");
            testMap.put(40, "d");
            for (Entry<Integer, String> entry : testMap.entrySet()) {
                if (entry.getValue().equals("c")) {
                    System.out.println(entry.getKey());
                }
            }
        }
    }
    

    Some additional info... May be useful to you

    如果您的hashmap非常大,则上面的方法可能不太好 . 如果您的hashmap包含唯一值映射的唯一键,则可以再维护一个包含从Value到Key的映射的hashmap .

    那就是你必须保持两个哈希图

    1. Key to value
    
    2. Value to key
    

    在这种情况下,您可以使用第二个hashmap来获取密钥 .

  • 71

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

    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);
    

相关问题