wake-up-neo.com

Java Hashmap: Wie bekomme ich einen Schlüssel vom Wert?

Wenn ich den Wert "foo" und einen HashMap<String> ftw habe, für den ftw.containsValue("foo")true zurückgibt, wie bekomme ich den entsprechenden Schlüssel? Muss ich die Hashmap durchlaufen? Was ist der beste Weg dies zu tun?

399
Nick Heiner

Wenn Sie die Commons Collections-Bibliothek anstelle der Standard-Java Collections-API verwenden, können Sie dies problemlos erreichen.

Die BidiMap - Schnittstelle in der Collections-Bibliothek ist eine bidirektionale Karte, mit der Sie einem Schlüssel einen Wert zuordnen können (wie bei normalen Karten). Außerdem können Sie einem Schlüssel einen Wert zuordnen, um Nachschlagen darin durchzuführen Beide Richtungen. Das Abrufen eines Schlüssels für einen Wert wird von der getKey () - Methode unterstützt.

Allerdings gibt es eine Einschränkung. Bidi-Maps können nicht mehrere Werte haben, die Schlüsseln zugeordnet sind. Wenn Ihr Datensatz keine 1: 1-Zuordnungen zwischen Schlüsseln und Werten enthält, können Sie keine Bidimaps verwenden.

Update

Wenn Sie sich auf die Java Collections-API verlassen möchten, müssen Sie die 1: 1-Beziehung zwischen Schlüsseln und Werten zum Zeitpunkt des Einfügens des Werts in die Map sicherstellen. Das ist leichter gesagt als getan.

Wenn Sie dies sichergestellt haben, verwenden Sie die Methode entrySet () , um die Gruppe der Einträge (Zuordnungen) in der Map zu erhalten. Wenn Sie das Set mit dem Typ Map.Entry erhalten haben, durchlaufen Sie die Einträge, vergleichen den gespeicherten Wert mit dem erwarteten und vergleichen den entsprechenden Schlüssel .

Update # 2

Unterstützung für Bidi-Karten mit Generika finden Sie in Google Guava und den refactored Commons-Collections -Bibliotheken (Letzteres ist kein Apache-Projekt). Vielen Dank an Esko für den Hinweis auf die fehlende generische Unterstützung in Apache Commons Collections. Durch die Verwendung von Sammlungen mit Generics wird der Code leichter gewartet.

199
Vineet Reynolds

Wenn Ihre Datenstruktur Many-to-one-Zuordnung zwischen Schlüsseln und Werten aufweist, sollten Sie Einträge durchlaufen und alle geeigneten Schlüssel auswählen:

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

Im Falle einer Eins-zu-Eins-Beziehung können Sie den ersten übereinstimmenden Schlüssel zurückgeben:

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

Für Guava-Benutzer kann auch BiMap nützlich sein. Zum Beispiel:

BiMap<Token, Character> tokenToChar = 
    ImmutableBiMap.of(Token.LEFT_BRACKET, '[', Token.LEFT_PARENTHESIS, '(');
Token token = tokenToChar.inverse().get('(');
Character c = tokenToChar.get(token);
576
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());
            }
        }
    }
}

Einige zusätzliche Informationen ... Kann für Sie nützlich sein

Die obige Methode ist möglicherweise nicht gut, wenn Ihre Hashmap wirklich groß ist. Wenn Ihre Hashmap einen eindeutigen Schlüssel für eine eindeutige Wertezuordnung enthält, können Sie eine weitere Hashmap verwalten, die eine Zuordnung von Wert zu Schlüssel enthält.

Das heißt, Sie müssen zwei Hashmaps verwalten

1. Key to value

2. Value to key 

In diesem Fall können Sie die zweite Hashmap verwenden, um den Schlüssel abzurufen.

71
Fathah Rehman P

Sie können sowohl das Schlüssel-Wert-Paar als auch das Inverse in Ihre Kartenstruktur einfügen

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

Wenn Sie map.get ("theValue") verwenden, wird "theKey" zurückgegeben.

Es ist eine schnelle und schmutzige Art und Weise, dass ich konstante Karten erstellt habe, die nur für ein paar wenige Datensätze funktionieren:

  • Enthält nur 1 bis 1 Paare
  • Der Wertesatz ist nicht mit dem Schlüsselsatz verbunden (1-> 2, 2-> 3).
18
Chicowitz

Ich denke, deine Entscheidungen sind

  • Verwenden Sie eine dafür entwickelte Kartenimplementierung, wie beispielsweise die BiMap von Google-Sammlungen. Beachten Sie, dass die Google Collections BiMap eindeutige Werte und Schlüssel erfordert, jedoch eine hohe Leistung in beide Richtungen bietet
  • Pflegen Sie manuell zwei Karten - eine für Schlüssel -> Wert und eine andere Karte für Wert -> Schlüssel
  • Durchlaufen Sie die Funktion entrySet() und finden Sie die Schlüssel, die dem Wert entsprechen. Dies ist die langsamste Methode, da die gesamte Auflistung durchlaufen werden muss, während die beiden anderen Methoden dies nicht erfordern.
17
Chi

Dekorieren Sie die Karte mit Ihrer eigenen Implementierung

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

Es gibt keine eindeutige Antwort, da mehrere Schlüssel demselben Wert zugeordnet werden können. Wenn Sie die Eindeutigkeit mit Ihrem eigenen Code erzwingen, empfiehlt es sich, eine Klasse zu erstellen, die zwei Hashmaps verwendet, um die Zuordnungen in beide Richtungen zu verfolgen.

11
recursive

Um alle Schlüssel zu finden, die diesem Wert zugeordnet sind, durchlaufen Sie alle Paare in der Hashmap mit map.entrySet().

11
wsorenson

Ich denke, das ist die beste Lösung, ursprüngliche Adresse: 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;
          }
        }

Eine einfache Verwendung: Wenn Sie alle Daten in hasMap eingeben und item = "Automobile" haben, suchen Sie den Schlüssel in hashMap. das ist eine gute lösung. 

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

Wenn Sie die Map in Ihrem eigenen Code erstellen, versuchen Sie, den Schlüssel und den Wert in der Map zusammenzufassen:

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

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

Wenn Sie einen Wert haben, haben Sie auch den Schlüssel.

7
David Tinker
for(int key: hm.keySet()) {
    if(hm.get(key).equals(value)) {
        System.out.println(key); 
    }
}
6
user309309

Es klingt wie der beste Weg für Sie, Einträge mit map.entrySet() zu durchlaufen, da map.containsValue() dies wahrscheinlich sowieso tut.

6
Jonas Klemming

Ich fürchte, Sie müssen nur Ihre Karte durchlaufen. Am kürzesten könnte ich mir einfallen lassen:

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

Verwendung von Java 8:

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

Für Android-Entwicklungs-Targeting-API <19 funktioniert die One-to-One-Beziehungslösung von Vitalii Fedorenko nicht, da Objects.equals nicht implementiert ist. Hier ist eine einfache Alternative:

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;
}
5
The Berga

Sie können das Folgende verwenden:

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);
            }
        }
    }
}
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;
}
2
Amazing India

Sie können den Schlüssel mithilfe von Werten mithilfe des folgenden Codes abrufen.

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

In Java8

map.entrySet().stream().filter(entry -> entry.getValue().equals(value))
    .forEach(entry -> System.out.println(entry.getKey()));
2
user3724331
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);
    }

}
2
margus
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

Meine 2 Cent. Sie können die Schlüssel in einem Array abrufen und dann das Array durchlaufen. Dies wirkt sich auf die Leistung dieses Codeblocks aus, wenn die Karte ziemlich groß ist. Dort erhalten Sie zuerst die Schlüssel in einem Array, was einige Zeit in Anspruch nehmen kann. Ansonsten sollte es für kleinere Karten in Ordnung sein.

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)            
}
1
Manu Bhat
/**
 * 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;
}
1
kanaparthikiran

Verwenden Sie eine dünne Hülle: 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;
   }
}
1
Jayen
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);
    }
}
1
Madhav

Ja, Sie müssen die Hashmap durchlaufen, es sei denn, Sie implementieren etwas in der Richtung der Vorschläge dieser verschiedenen Antworten. Anstatt mit entrySet herumzuspielen, würde ich einfach keySet () abrufen, diesen Satz durchlaufen und den (ersten) Schlüssel behalten, mit dem Sie Ihren passenden Wert erhalten. Wenn Sie alle Schlüssel benötigen, die diesem Wert entsprechen, müssen Sie natürlich das Ganze tun.

Wie Jonas vorschlägt, ist dies möglicherweise bereits das, was die Containersvalue-Methode ausführt, so dass Sie diesen Test einfach alle zusammen überspringen und die Iteration jedes Mal wiederholen (oder der Compiler beseitigt vielleicht bereits die Redundanz).

Auch relativ zu den anderen Antworten, wenn Ihre umgekehrte Karte so aussieht

Map<Value, Set<Key>>

sie können mit nicht-eindeutigen Schlüssel-> Wertzuordnungen umgehen, wenn Sie diese Funktion benötigen (zum Entschlüsseln). Dies würde eine gute Lösung für jede der hier vorgeschlagenen Lösungen mit zwei Karten sein.

1
Carl

Dies beantwortet zwar die Frage nicht direkt, ist aber verwandt.

Auf diese Weise müssen Sie nicht ständig erstellen/iterieren. Erstellen Sie einfach einmal eine Umkehrkarte und erhalten Sie, was Sie brauchen.

/**
 * 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
Markymark
  1. Wenn Sie den Schlüssel aus dem Wert erhalten möchten, ist es am besten, Bidimap (bidirektionale Karten) zu verwenden. Sie können den Schlüssel aus dem Wert in der Zeit O(1) erhalten.

    Der Nachteil dabei ist jedoch, dass Sie nur eindeutige Keysets und Werte verwenden können.

  2. Es gibt eine Datenstruktur namens Table in Java, die nichts weiter als eine Karte von Karten ist

    Tabelle <A, B, C> == Karte <A, Karte <B, C>>

    Hier können Sie map<B,C> erhalten, indem Sie T.row(a); abfragen, und Sie können map<A,C> auch abfragen, indem Sie T.column(b); abfragen.

Fügen Sie in Ihrem speziellen Fall C als eine Konstante ein.

Also wie <a1, b1, 1> <a2, b2, 1>, ...

Wenn Sie also via T.row (a1) ---> die Karte von -> erhalten, erhalten Sie die zurückgegebene Karte.

Wenn Sie den Schlüsselwert finden müssen, gibt T.column (b2) -> die Karte von -> Schlüsselmenge der zurückgegebenen Karte abrufen.

Vorteile gegenüber dem vorigen Fall: 

  1. Kann mehrere Werte verwenden.
  2. Effizienter bei der Verwendung großer Datensätze.
0
Batman

Der Wert sei maxValue.

Set keySet = map.keySet();

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

versuche dies:

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

Ich denke, keySet () kann gut die Schlüssel finden, die dem Wert zugeordnet sind, und einen besseren Codierstil haben als entrySet () .

Ex:

Angenommen, Sie haben eine HashMap map, ArrayList res, einen Wert , nach dem Sie alle SchlüsselZuordnungen suchen möchten, und dann die Schlüssel für res speichern.

Sie können unten Code schreiben:

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

verwenden Sie nicht entrySet () unten:

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

Ich hoffe es hilft :)

0
FrancisGeek

Beachten Sie, dass Apache Collections seit dieser Frage Generic BidiMaps unterstützt. Daher sind einige der am besten bewerteten Antworten in diesem Punkt nicht mehr zutreffend.

Für eine serialisierte BidiMap, die auch doppelte Werte unterstützt (1-to-many-Szenario), sollten Sie auch MapDB.org berücksichtigen.

0
kervin

Soweit ich weiß, werden Schlüssel und Werte einer HashMap nicht gemischt, wenn Sie sie als Arrays darstellen:

hashmap.values().toArray()

und

hashmap.keySet().toArray()

Der folgende Code (seit Java 8) sollte also wie erwartet funktionieren:

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

( WARNUNG! ) arbeitet jedoch 2-3 Mal langsamer als die Iteration.

0
MilTy