Java Hashmap: How to get key from value?
如果我有值
如果您的数据结构在键和值之间有多对一的映射,您应该遍历条目并选择所有合适的键:
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 |
在这种情况下,您可以使用第二个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); } } |
要找到映射到该值的所有键,请使用
没有明确的答案,因为多个键可以映射到同一个值。如果使用自己的代码强制实现惟一性,最好的解决方案是创建一个类,该类使用两个哈希映射来跟踪两个方向的映射。
我认为这是最好的解决方案,原始地址: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 |
当你有一个值时,你也有这个键。
听起来最好的方法是使用
1 2 3 4 5 |
恐怕你只需要重复你的地图。我能想到的最短的:
1 2 3 4 5 6 7 |
对于针对API<19的Android开发,Vitalii Fedorenko一对一关系解决方案不起作用,因为
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 |
您可以使用以下内容:
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 |
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 |
是的,除非您按照这些不同的答案的建议来实现某些东西,否则您必须循环遍历哈希图。我不需要修改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 |
但是,(警告!)它比迭代慢2-3倍。
需要注意的是,由于这个问题,Apache集合支持通用bidimap。因此,一些投票结果最高的答案在这一点上不再准确。
对于也支持重复值(1对多方案)的序列化bidimap,还应考虑mapdb.org。
如果您想从值中获取键,最好使用bidimap(双向映射),您可以在o(1)时间内从值中获取键。
但是,这样做的缺点是您只能使用唯一的键集和值集。
在Java中有一个称为表的数据结构,它只不过是地图的映射。
在特殊情况下,插入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 |
1 2 3 4 5 6 7 |