tags:

views:

10988

answers:

11

If I have the value "foo", and a hashmap 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?

+2  A: 

There is no unambiguous answer, because multiple keys can map to the same value. If you are enforcing unique-ness with your own code, the best solution is to create a class that uses two Hashmaps to track the mappings in both directions.

recursive
+4  A: 

To find all the keys that map to that value, iterate through all the pairs in the hashmap, using map.entrySet().

wsorenson
+2  A: 

It sounds like the best way is for you to iterate over entries using map.entrySet() since map.containsValue() probably does this anyway.

Jonas Klemming
Yes, 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.
CPerkins
Well, 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.
Jonas Klemming
+10  A: 

If you choose to use the Commons Collections library instead of the standard Java Collections API, you can achieve this with ease.

The BidiMap interface in the Collections library is a bi-directional map, allowing your 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 bidimaps.

Update

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.

Update #2

Support for bidi maps with generics can be found in Google Collections 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.

Vineet Reynolds
...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);
Esko
Yes, 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 @ http://sourceforge.net/projects/collections/
Vineet Reynolds
The Google Collections are **not** a refactored version of Commons-Collections.
Willi
+3  A: 

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.
Chi
+3  A: 

If you build the map in your own code, try putting the key and value in the map together:

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

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

Then when you have a value, you also have the key.

David Tinker
Clever, but what if there are 2 or more KeyValue objects containing the same value? Which key should one choose?
Vineet Reynolds
A: 

Yes, you have to loop through the hashmap, unless you implement something along the lines of what these various answers suggest. Rather than fiddling with the entrySet, I'd just get the keySet(), iterate over that set, and keep the (first) key that gets you your matching value. If you need all the keys that match that value, obviously you have to do the whole thing.

As Jonas suggests, this might already be what the containsValue method is doing, so you might just skip that test all-together, and just do the iteration every time (or maybe the compiler will already eliminate the redundancy, who knows).

Also, relative to the other answers, if your reverse map looks like

Map<Value, Set<Key>>

you can deal with non-unique key->value mappings, if you need that capability (untangling them aside). That would incorporate fine into any of the solutions people suggest here using two maps.

Carl
+5  A: 

If your data structure has many to one mapping between keys and values you should iterate over all entries and pick 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 (entry.getValue().equals(value)) {
             keys.add(entry.getKey());
         }
     }
     return keys;
}
Vitalii Fedorenko
+1 for being the only one that showed how you can do this using the Java API.
Shervin
+1, was going to write this myself, but you propose a very elegant solution
Peter Perháč
A: 

I'm afraid you'll just have to iterate your map. Shortest I could come up with:

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();
    }
}
André van Toly
A: 

how can i convert hashmap to xml in java?

hasti
Put this in its own question.
Rosarch
A: 

You can get the key using values using following code..

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