Java HASMAP:如何从值中获取密钥?

Java Hashmap: How to get key from value?

如果我有值"foo",和ftw.containsValue("foo")返回trueHashMap ftw,我如何获得相应的键?我需要循环遍历哈希图吗?最好的方法是什么?


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

1
2
3
4
5
6
7
8
9
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;
}

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

1
2
3
4
5
6
7
8
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中:

1
2
3
4
5
6
7
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());
}

此外,对于番石榴用户来说,BIMAP可能很有用。例如:

1
2
3
4
BiMap<Token, Character> tokenToChar =
    ImmutableBiMap.of(Token.LEFT_BRACKET, '[', Token.LEFT_PARENTHESIS, '(');
Token token = tokenToChar.inverse().get('(');
Character c = tokenToChar.get(token);


如果您选择使用CAMONS集合库而不是标准Java集合API,那么您可以轻松实现这一点。

集合库中的bidimap接口是一个双向映射,允许您将一个键映射到一个值(如普通映射),也允许您将一个值映射到一个键,从而允许您在两个方向上执行查找。getkey()方法支持获取值的键。

但是有一个警告,bidi映射不能有多个值映射到键,因此,除非数据集在键和值之间有1:1的映射,否则不能使用bidi maps。

更新

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

确保这一点后,使用entryset()方法获取映射中的一组条目(映射)。一旦获得了类型为map.entry的集合,就可以遍历这些条目,将存储值与预期值进行比较,并获得相应的键。

更新第2号

对具有泛型的bidi映射的支持可以在google guava和重构的commons集合库中找到(后者不是Apache项目)。感谢Esko指出ApacheCommons集合中缺少的通用支持。将集合与泛型一起使用可以提高代码的可维护性。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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());
            }
        }
    }
}

其他信息…可能对你有用

如果散列图很大,上面的方法可能不太好。如果哈希映射包含唯一值到唯一值映射的唯一键,则可以再维护一个包含从值到键映射的哈希映射。

那就是你必须维护两个哈希图

1
2
3
1. Key to value

2. Value to key

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


我认为你的选择是

  • 使用为此而构建的映射实现,比如来自Google Collections的BIMAP。请注意,google collections bimap需要值和键的唯一性,但它在两个方向上都提供了高性能。
  • 手动维护两个映射-一个用于key->value,另一个用于value->key
  • 遍历entrySet()并查找与值匹配的键。这是最慢的方法,因为它需要遍历整个集合,而其他两个方法不需要。


可以将键、值对及其逆项插入到映射结构中。

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

使用map.get("thevalue")将返回"thekey"。

我制作常量映射是一种快速而肮脏的方法,它只适用于选定的几个数据集:

  • 仅包含1到1对
  • 值集与键集不相交(1->2,2->3打断它)


用自己的实现来装饰地图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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);
    }
}


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


没有明确的答案,因为多个键可以映射到同一个值。如果使用自己的代码强制实现惟一性,最好的解决方案是创建一个类,该类使用两个哈希映射来跟踪两个方向的映射。


我认为这是最好的解决方案,原始地址:java2s

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
    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中查找其键。这是个好办法。

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


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

1
2
3
4
5
6
7
public class KeyValue {
    public Object key;
    public Object value;
    public KeyValue(Object key, Object value) { ... }
}

map.put(key, new KeyValue(key, value));

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


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


1
2
3
4
5
for(int key: hm.keySet()) {
    if(hm.get(key).equals(value)) {
        System.out.println(key);
    }
}

恐怕你只需要重复你的地图。我能想到的最短的:

1
2
3
4
5
6
7
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();
    }
}

对于针对API<19的Android开发,Vitalii Fedorenko一对一关系解决方案不起作用,因为Objects.equals没有实现。这里有一个简单的选择:

1
2
3
4
5
6
7
8
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;
}


使用Java 8:

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


您可以使用以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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);
            }
        }
    }
}


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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);
    }

}


在Java8中

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


1
2
3
4
5
6
7
8
9
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;
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
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
     */

}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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);
    }
}

使用薄包装:hmap

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
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;
   }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
 * 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;
}


我的2美分。您可以获取数组中的键,然后在数组中循环。如果映射非常大,这将影响此代码块的性能,其中首先获取数组中的键可能会花费一些时间,然后进行循环。否则,对于较小的地图,应该可以。

1
2
3
4
5
6
7
8
9
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)            
}


是的,除非您按照这些不同的答案的建议来实现某些东西,否则您必须循环遍历哈希图。我不需要修改entryset,只需要获取key set(),迭代该集合,并保留(第一个)获得匹配值的键。如果您需要所有与该值匹配的键,显然您必须完成全部工作。

正如jonas所建议的,这可能已经是containsValue方法所做的,所以您可以一起跳过该测试,每次都进行迭代(或者编译器可能已经消除了冗余,谁知道呢)。

另外,相对于其他答案,如果你的反向图看起来像

1
Map<Value, Set<Key>>

如果需要这种功能(将它们放在一边),您可以处理非唯一键->值映射。这将把罚款纳入任何解决方案,人们建议这里使用两个地图。


虽然这不能直接回答问题,但它是相关的。

这样就不需要继续创建/迭代。只需创建一次反向映射,就可以得到所需的内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/**
 * 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;
}

据我所知,当您将哈希映射的键和值表示为数组时,它们是不混合的:

1
hashmap.values().toArray()

1
hashmap.keySet().toArray()

因此,下面的代码(因为Java 8)应该按照预期工作:

1
2
3
4
public Object getKeyByFirstValue(Object value) {
    int keyNumber =  Arrays.asList(hashmap.values().toArray()).indexOf(value);
    return hashmap.keySet().toArray()[keyNumber];
}

但是,(警告!)它比迭代慢2-3倍。


需要注意的是,由于这个问题,Apache集合支持通用bidimap。因此,一些投票结果最高的答案在这一点上不再准确。

对于也支持重复值(1对多方案)的序列化bidimap,还应考虑mapdb.org。


  • 如果您想从值中获取键,最好使用bidimap(双向映射),您可以在o(1)时间内从值中获取键。

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

  • 在Java中有一个称为表的数据结构,它只不过是地图的映射。

    ==map>

    这里可以通过查询T.row(a);得到map,也可以通过查询T.column(b);得到map

  • 在特殊情况下,插入c作为常量。

    所以,它就像,…

    因此,如果您通过t.row(a1)找到--->返回映射--->获取键集,则返回该映射。

    如果需要查找键值,则t.column(b2)->返回返回的映射——>获取返回映射的键集。

    与前一个案例相比的优势:

  • 可以使用多个值。
  • 使用大型数据集时效率更高。

  • 我认为keyset()可以很好地找到映射到值的键,并且具有比entryset()更好的编码风格。

    前任:

    假设您有一个hashmap map,arraylist res,一个您想要查找所有键映射到的值,然后将键存储到res。

    您可以在下面编写代码:

    1
    2
    3
    4
    5
        for (int key : map.keySet()) {
            if (map.get(key) == value) {
                res.add(key);
            }
        }

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

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

    希望有帮助:)


    试试这个:

    1
    2
    3
    4
    5
    6
    7
    static String getKeyFromValue(LinkedHashMap<String, String> map,String value) {
        for (int x=0;x<map.size();x++){
            if( String.valueOf( (new ArrayList<String>(map.values())).get(x) ).equals(value))
                return String.valueOf((new ArrayList<String>(map.keySet())).get(x));
        }
        return null;
    }

    1
    2
    3
    4
    5
    6
    7
    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();
    }
    }