Java Hashmap: How to get key from value?
Solution 1
If you choose to use the Commons Collections library instead of the standard Java Collections framework, you can achieve this with ease.
The BidiMap
interface in the Collections library is a bi-directional map, allowing you to map a key to a value (like normal maps), and also to map a value to a key, thus allowing you to perform lookups in both directions. Obtaining a key for a value is supported by the getKey()
method.
There is a caveat though, bidi maps cannot have multiple values mapped to keys, and hence unless your data set has 1:1 mappings between keys and values, you cannot use bidi maps.
If you want to rely on the Java Collections API, you will have to ensure the 1:1 relationship between keys and values at the time of inserting the value into the map. This is easier said than done.
Once you can ensure that, use the entrySet()
method to obtain the set of entries (mappings) in the Map. Once you have obtained the set whose type is Map.Entry
, iterate through the entries, comparing the stored value against the expected, and obtain the corresponding key.
Support for bidi maps with generics can be found in Google Guava and the refactored Commons-Collections libraries (the latter is not an Apache project). Thanks to Esko for pointing out the missing generic support in Apache Commons Collections. Using collections with generics makes more maintainable code.
Since version 4.0 the official Apache Commons Collections™ library supports generics.
See the summary page of the "org.apache.commons.collections4.bidimap" package for the list of available implementations of the BidiMap
, OrderedBidiMap
and SortedBidiMap
interfaces that now support Java generics.
Solution 2
If your data structure has many-to-one mapping between keys and values you should iterate over entries and pick all suitable keys:
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;
}
In case of one-to-one relationship, you can return the first matched key:
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;
}
In 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());
}
Also, for Guava users, BiMap may be useful. For example:
BiMap<Token, Character> tokenToChar =
ImmutableBiMap.of(Token.LEFT_BRACKET, '[', Token.LEFT_PARENTHESIS, '(');
Token token = tokenToChar.inverse().get('(');
Character c = tokenToChar.get(token);
Solution 3
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
Above method may not be good if your hashmap is really big. If your hashmap contain unique key to unique value mapping, you can maintain one more hashmap that contain mapping from Value to Key.
That is you have to maintain two hashmaps
1. Key to value
2. Value to key
In that case you can use second hashmap to get key.
Solution 4
You could insert both the key,value pair and its inverse into your map structure
map.put("theKey", "theValue");
map.put("theValue", "theKey");
Using map.get("theValue") will then return "theKey".
It's a quick and dirty way that I've made constant maps, which will only work for a select few datasets:
- Contains only 1 to 1 pairs
- Set of values is disjoint from the set of keys (1->2, 2->3 breaks it)
Solution 5
I think your choices are
- Use a map implementation built for this, like the BiMap from google collections. Note that the google collections BiMap requires uniqueless of values, as well as keys, but it provides high performance in both directions performance
- Manually maintain two maps - one for key -> value, and another map for value -> key
- Iterate through the
entrySet()
and to find the keys which match the value. This is the slowest method, since it requires iterating through the entire collection, while the other two methods don't require that.
![Nick Heiner](https://i.stack.imgur.com/3bnPx.jpg?s=256&g=1)
Nick Heiner
JS enthusiast by day, horse mask enthusiast by night. Talks I've Done
Updated on December 29, 2021Comments
-
Nick Heiner over 2 years
If I have the value
"foo"
, and aHashMap<String> ftw
for whichftw.containsValue("foo")
returnstrue
, how can I get the corresponding key? Do I have to loop through the hashmap? What is the best way to do that? -
Vineet Reynolds almost 15 yearsClever, but what if there are 2 or more KeyValue objects containing the same value? Which key should one choose?
-
Esko almost 15 years...and if you like Generics and all that modern stuff, Google Collections has BiMap where you can get key matching specified value by calling biMap.inverse().get(value);
-
Vineet Reynolds almost 15 yearsYes, Apache Commons Collections doesn't support generics. However, there is Google Collections as you've pointed out (which I don't use yet - no 1.0 release yet), and there is the refactored Commons-Collections with support for Generics. You'll find this as a Sourceforge project @ sourceforge.net/projects/collections
-
CPerkins almost 15 yearsYes, that's exactly what it does. But of course it returns true as soon as it finds one value for which .equals is true, as opposed to what OP will probably need to do.
-
Jonas K almost 15 yearsWell, iterating over entries can return with key as soon as it finds a matching value too. Multiple matches did not seem to be a concern.
-
whiskeysierra almost 14 yearsThe Google Collections are not a refactored version of Commons-Collections.
-
Qiang Li almost 13 years@Vineet, I don't see how this approach solves the OP's question. what did you mean by "Then when you have a value, you also have the key."?
-
huff almost 13 years@whiskeysierra: I don't think anyone is (currently) saying so.
-
Jonathan over 11 yearsI think this answer could be improved by adding an explanation.
-
jlordo over 11 years-1. I tested it with
String
as key and value. When I callmap.add("1", "2"); map.add("1","3");
then I can callmap.getKey("2");
and retrieve"1"
, even though"1"
is the key for"3"
. -
tasomaniac almost 11 yearsCan you say anything about the performance? What will be more optimized? This or BidiMap?
-
arjacsoh almost 11 yearsI have thought the same solution, I have upvoted it of course but I doubt on its efficiency when it comes to really large Collections.
-
Ogre Psalm33 over 10 yearsIt looks like Apache Commons will get a BidiMap with generics support in release 4.0 (currently in alpha release): commons.apache.org/proper/commons-collections/javadocs/…
-
Chicowitz over 9 years@Jonathan the idea behind this class is to keep another HashMap with the reverse mappings so that in addition to retrieving a value from a key, you can retrieve a key from a value. The T1 & T2 classes are a bit confusing; maybe literally name them Key & Value instead? Although I would expect the ability to receive more than one value or more than one key in return, depending on the data & what you want. Use with caution
-
Price over 9 yearsIs having two separate lists for keys and values a bad way to solve this problem? If you know the index of a key in the list of keys, you can get the value from that same index in the values list.
-
jlordo over 9 years@theknightwhosaysni "1" is not the key for "2" (anymore). This is also the answer to your question, calling
getValue("1")
will return3
. -
Chicowitz over 9 yearsSorry jlordo, I was mistaken about standard Hashmap behavior: you are correct in that adding a new value for a key should replace the old value
-
Joehot200 over 9 yearsThis solution is horribly intensive, to the point where it is impractical on large HashMaps.
-
veer7 about 9 yearsstackoverflow.com/questions/4553624/hashmap-get-put-complexity HashMap has time complexity
o(1)
. If you are iterating over the values then it will kill the performance. If you want abetter performance
and has aone-one
relationship, you can useanother map
wherevalue is a key
-
Holger about 9 yearsI recommend to replace
.filter(entry -> entry.getValue().equals(value))
with.filter(entry ->
Objects.equals
(entry.getValue(), value))
as no statement aboutnull
ability was made. Further, you can replace.map(entry -> entry.getKey())
with.map(Map.Entry::getKey)
-
Viktor Vix Jančík about 9 yearsApache Collections now supports generics commons.apache.org/proper/commons-collections/javadocs/…
-
Luis A. Florit over 8 yearsThis is not really correct. This does not only requires 1-1, but also that the set of values is disjoint from the set of keys. You can't apply this to the bijective map {1 -> 2, 2 -> 3}: 2 is both a value and a key.
-
Tom almost 8 yearsAnd why should someone use that approach? As you already said, the performance would be worse, than in other approaches.
-
Fran Marzoa over 7 yearsI think this is an interesting approach, though since the relation has to be 1:1, I'd get rid of HashMap altogether and implement Map<K,V> interface instead so to avoid duplicates of both, values and keys.
-
Tom over 7 yearsIt is nice that you want to provide useful stuff, but it shouldn't be a "code only" answer and the code itself shouldn't be full of code smells, either.
-
ponderingdev over 7 yearsi'm having difficulty understanding the <T, E> notation before Set<T> getKeysByValue()...what's the point....different way to do it without using that? thanks
-
Toby Wilson over 7 yearsThis solution works for me; also developing for an archaeological Android version, in my case to get the key of a Google Map marker held in a Map in an "onMarkerClick" event. Iterating the entrySet works; but iterating the keys and matching them to entries with get(), and comparing the output, didn't.
-
Aquarius Power over 7 yearsguava's HashBiMap.create()
-
Admin about 7 yearsMap<String, Integer> map = new HashMap<String, Integer>(); map.put("A", 1); map.put("B", 2); map.put("C", 3); map.put("D", 4); // System.out.println(map); System.out.println(getKey(map, "4"));
-
Cà phê đen about 7 yearsWhat happens if multiple keys have the same value?
-
Admin about 7 yearsWhen u pass the multiple keys have the same value, we will get the last key as result. example: A 1, B 1, C 1, D 2 output: if we pass the 1 value , output will be C
-
Niels Doucet almost 7 years@AmazingIndia This is not guaranteed and completely depends on the specific map implementation. HashMap for instance does not guarantee an order, so you have no idea what output will be returned here.
-
frododot over 5 years
map.get(key) == value
is not a good idea when checking equality of objects, as you are comparing references. Object equality should always use their.equals()
-
frododot over 5 years@Anton, true unless
value
has been interned. -
Aliton Oliveira about 4 yearsCall requires API Level 24: java.util.Collection#stream
-
Admin over 2 yearsAs it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.