Java Hashmap: How to get key from value?

Viewed 1102963

If I have the value "foo", and a HashMap<String> ftw for which ftw.containsValue("foo") returns true, how can I get the corresponding key? Do I have to loop through the hashmap? What is the best way to do that?

39 Answers

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)

I think keySet() may be well to find the keys mapping to the value, and have a better coding style than entrySet().

Ex:

Suppose you have a HashMap map, ArrayList res, a value you want to find all the key mapping to , then store keys to the res.

You can write code below:

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

rather than use entrySet() below:

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

Hope it helps :)

Simplest utility method to fetch a key of a given value from a Map:

public static void fetchValue(Map<String, Integer> map, Integer i)
{   
Stream stream = map.entrySet().stream().filter(val-> val.getValue().equals(i)).map(Map.Entry::getKey);
stream.forEach(System.out::println);    
}

detailed explaination:

  1. Method fetchValue accepts the map, which has String as key and Integer as value.

  2. Then we use entryset().stream() to convert result into a stream.

  3. Next we use filter (intermediate operation) which gives us a value that is equal to the second argument.

  4. Finally, we use forEach(final operation) to print our end result.

Found too many answers. Some were really great. But I was particularly looking for a way, so that I can get the value using loops.

So here is finally what I did: For a HashMap 1-to-1 relation:

    Map<String, String> map = new HashMap<String, String>();
    
    map.put("abc", "123");
    map.put("xyz", "456");
    
    for(Entry<String, String> entry : map.entrySet()) {
        if(entry.getValue().equalsIgnoreCase("456")) {
            System.out.println(entry.getKey());
        }
    }

Output: "xyz"

For a HashMap 1-to-many relation:

    Map<String, ArrayList<String>> service = new HashMap<String, ArrayList<String>>();
    
    service.put("abc", new ArrayList<String>());
    service.get("abc").add("a");
    service.get("abc").add("b");
    service.get("abc").add("c");
    
    service.put("xyz", new ArrayList<String>());
    service.get("xyz").add("x");
    service.get("xyz").add("y");
    service.get("xyz").add("z");
    
    for(Entry<String, ArrayList<String>> entry : service.entrySet()) {
        ArrayList<String> values = entry.getValue();
        for(String value : values) {
            if(value.equalsIgnoreCase("x")) {
                System.out.println(entry.getKey());
            }
        }
        
    }

Output: xyz

-Thanks

While this does not directly answer the question, it is related.

This way you don't need to keep creating/iterating. Just create a reverse map once and get what you need.

/**
 * 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;
}

try this:

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

As far as I know keys and values of a HashMap are not mixed when you represent them as arrays:

hashmap.values().toArray()

and

hashmap.keySet().toArray()

So the following code (since java 8) should work as expected:

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

However, (WARNING!) it works 2-3 times slower than iteration.

Let the value be maxValue.

Set keySet = map.keySet();

keySet.stream().filter(x->map.get(x)==maxValue).forEach(x-> System.out.println(x));

lambda w/o use of external libraries
can deal with multiple values for one key (in difference to the BidiMap)

public static List<String> getKeysByValue(Map<String, String> map, String value) {
  List<String> list = map.keySet().stream()
      .collect(groupingBy(k -> map.get(k))).get(value);
  return (list == null ? Collections.emptyList() : list);
}

gets a List containing the key(s) mapping value
for an 1:1 mapping the returned list is empty or contains 1 value

let see my example

Map<String, String> mapPeopleAndCountry = new HashMap<>();
mapPeopleAndCountry.put("Matis", "Lithuania");
mapPeopleAndCountry.put("Carlos", "Honduras");
mapPeopleAndCountry.put("Teboho", "Lesotho");
mapPeopleAndCountry.put("Marielos", "Honduras");


List<String> peopleInHonduras = mapPeopleAndCountry.keySet()
    .stream()
    .filter(r -> mapPeopleAndCountry.get(r)
                .equals("Honduras"))
    .stream(Collectors.toList());

// will return ["Carlos", "Marielos"]

Note: untested, may contains typo

You can also do that work: First : put map (key, value) Second : to update the key you need to remove expression Third : and put a new key with the oldValue

Related