Java Hashmap: how to get the key from the value of?

If my values "foo", and ftw.containsValue("foo")return trueof HashMap<String> ftw, how to obtain the corresponding keys? Do I have to traverse a hash map? What is the best method?


#1st Floor

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

#2nd Floor

There is no clear answer, because multiple keys can be mapped to the same value. If you want to use your own code to enforce uniqueness, the best solution is to create a two Hashmap class map to track in both directions.


#3rd floor

To find all the keys are mapped to the value, use the map.entrySet()traverse hash map all right.


#4th floor

The best way is to use sounds map.entrySet()to traverse entry, as map.containsValue()may still do so.


#5th Floor

If you choose to use Commons Collections library instead of the standard Java Collections API, you can easily accomplish this.

Collections library BidiMap interface is bidirectional mapping allows you to map to the key value (such as the normal mapping), it can also be mapped to the key value, allowing you to perform a lookup in both directions. getKey () method to support access to key values.

Note that, bidi mapping can not map multiple values ​​to the keys, so unless you have a set of data between the key and value: 1 mapping, or you can not use bidimaps.

Updates

If you want to rely on Java Collections API, you must ensure that the bond between the 1 and the value when the value is inserted map: 1 relationship. easy to say, hard to do.

Once ensures use, use entrySet () method to obtain a set of entries in the Map (map). Type is obtained Map.Entry after collection, iterate through entries, the value stored in the expected value, and obtains the corresponding Key .

Update # 2

Can Google Guava and reconstruction of Commons-Collections find support for bidi maps with generics in the library (which is not the Apache project). Thank Esko Apache Commons Collections noted the lack of universal support. The use can code easier to maintain, together with the generic set.


#6th floor

I think your choice is

  • Constructed for this purpose using a map to achieve, such as Google set BiMap . Please note, Google BiMap set of requirements and key values are unique, but the two-way performance is outstanding
  • Maintenance Manual two mapping - mapping to a key-> value, is mapped to the other value-> key
  • Traversal entrySet()and find the key that matches the value. This is the slowest method because it needs to traverse the entire collection, while the other two methods do not.

#7th floor

If you use your own code to build the map, try the key and value into the map:

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 will also have a key.


Building # 8

Yes, unless you implement some of these different answers follow the recommended way, or you must traverse the hash map. I just need to get keySet (), then walk through the collection and retention (first) button you can get a matching value, without having to fiddle with entrySet. If you need all the keys that match the value, then obviously you have to do the whole thing.

As Jonas (Jonas) suggests, this effect may already be containsValue method, so you may completely skip this test, and each time iterating (or the compiler has eliminated redundant, this is well known).

In addition, with respect to the other answers, if you reverse mapping looks like

Map<Value, Set<Key>>

If you need this feature, you can handle non-unique key-> value mapping (set them aside). This can be well integrated into any solution that people use two maps proposed.


House # 9

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

}

#10th floor

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

House # 11

You can use the buttons, and the value of the reverse structure is inserted into the map

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

Then use map.get ( "theValue") will return "theKey".

I made a constant mapping is a quick and dirty way, it only applies to a small number of data sets:

  • Containing only 1 to 1
  • And key value set disjoint sets (1-> 2,2-> 3 off key)

House # 12

In java8

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

House # 13

I think this is the best solution to the original address: Java2s

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

A simple usage: If all the data into hasMap, and have item = "Automobile", you will find their keys in the hashMap. That is a good solution.

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

House # 14

If your data structure between the key and the value of many- mapping should traverse all entries and select the appropriate key:

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

If you are one to one relationship, you can return the first matching 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 in:

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

Similarly, for Guava user, BiMap may be useful. E.g:

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

House # 15

I'm afraid you just need to iterate over the map. I can think of is the shortest time:

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

House # 16

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

House # 17

You can use the following code to obtain the key usage value.

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

House # 18

It is worth noting that, due to this problem, Apache Collections support the Generic BidiMaps . Therefore, at this point, some of the most voted answer is no longer accurate.

For the sequence of duplicate values also supports BidiMap (many programs), consider MapDB.org .


House # 19

for(int key: hm.keySet()) {
    if(hm.get(key).equals(value)) {
        System.out.println(key); 
    }
}

House # 20

Use Java 8:

ftw.forEach((key, value) -> {
    if (value.equals("foo")) {
        System.out.print(key);
    }
});

House # 21

For API developed for Android <19, Vitalii Fedorenko one relationship solution does not work, because unrealized Objects.equals. This is a simple choice:

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

House # 22

Decorated with their own realization map

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

House # 23

My 2 cents. You can get an array of keys, and then cycle in the array. If the map is large, it will affect the performance of this code block, in which case, you must first obtain an array of keys, which may take some time, and then the cycle. Otherwise, for smaller maps should be no problem.

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

House # 24

  1. If you want to acquire the key value, it is preferable to use bidimap (bidirectional mapping), can obtain the key from the value in O (1) time.

    However, the disadvantage of this is that you can only use a unique set of keys and values ​​set.

  2. Java has called Table data structure, but it is similar to the map of the map

    Table <A, B, C> == map <A, mapping <B, C >>

    Here, you can query T.row(a);to obtain map<B,C> T.row(a);, can also query T.column(b);to obtainmap<A,C> T.column(b);

In special cases, the constant C is inserted.

Thus, it is similar to <a1, b1,1> <a2, b2,1>, ...

Therefore, if by T.row (a1) Find ---> Returns -> map, this return key set is acquired map.

If you need to find the key, then T.column (b2) -> Returns -> map, get set to return key mapping.

With advantages over previously:

  1. A plurality of values ​​may be used.
  2. More efficiently when working with large data sets.

House # 25

You can use the following:

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

House # 26

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

House # 27

I think keySet () may well find that mapped to the key value, and the ratio entrySet () better coding style.

E.g:

Suppose you have a HashMap mapping ArrayList RES , the value is that you want to find all the keys mapped value , then the key is stored in the RES .

You can write code below:

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

Instead of using the following entrySet ():

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

I am hoping to help you :)


House # 28

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

This way, you do not need to continue creating / iteration. Just create a reverse mapping to obtain the desired content.

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

House # 29

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

Other information may be useful for you ...

If your hash map is large, the above method may not be very good. If your hash table contains the unique key is mapped to a unique value, you can then maintain a hash table, which contains a mapping from keys to values.

That's what you have to maintain two hash map

1. Key to value

2. Value to key 

In this case, you can use a second hash map to get the keys.


House # 30

A thin wrapper: HMAP

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;
   }
}
Original articles published 0 · won praise 2 · Views 7766

Guess you like

Origin blog.csdn.net/asdfgh0077/article/details/104114650