Java Hashmap: Wie erhalte ich den Schlüssel vom Wert?

450

Wie kann ich den entsprechenden Schlüssel erhalten, wenn ich den Wert habe "foo"und a HashMap<String> ftwfür den ftw.containsValue("foo")zurückgegeben truewird? Muss ich die Hashmap durchlaufen? Was ist der beste Weg das zu tun?

Nick Heiner
quelle
72
Beachten Sie, dass es keinen einzelnen entsprechenden Schlüssel gibt. Möglicherweise sind mehrere Schlüssel demselben Wert zugeordnet.
CPerkins
1
@CPerkins, aber für Hashmaps wie <strFilename, Reader> und viele andere 1 zu 1 ist es sehr nützlich.
Wassermann Macht
Wenn Sie eine kleine Sammlung von Gegenständen haben, sollten Sie eine Konstante erstellen public static final String TIME = "time";undproperties.put(TIME, PbActivityJpa_.time);
Basheer AL-MOMANI
Wahrscheinlich könnte dies Ihnen helfen, die Daten von der Karte zu erhalten, und Sie können auch eine Art Verarbeitung durchführen. frugalisminds.com/java/java-8-stream-map-examples
Sanjay-Dev

Antworten:

215

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

Die BidiMap- Oberfläche in der Sammlungsbibliothek ist eine bidirektionale Zuordnung, mit der Sie einen Schlüssel einem Wert zuordnen können (wie bei normalen Zuordnungen) und einen Wert einem Schlüssel zuordnen können, sodass Sie in beide Richtungen nachschlagen können. Das Abrufen eines Schlüssels für einen Wert wird von der Methode getKey () unterstützt .

Es gibt jedoch eine Einschränkung: Bei Bidi-Karten können nicht mehrere Werte auf Schlüssel abgebildet werden. Daher können Sie keine Bidimaps verwenden, es sei denn, Ihr Datensatz enthält 1: 1-Zuordnungen zwischen Schlüsseln und Werten.

Aktualisieren

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 Zuordnung sicherstellen. Das ist leichter gesagt als getan.

Wenn Sie dies sicherstellen können, verwenden Sie die entrySet () -Methode , um die Einträge (Zuordnungen) in der Map abzurufen . Wenn Sie die Menge mit dem Typ Map.Entry erhalten haben , durchlaufen Sie die Einträge, vergleichen Sie den gespeicherten Wert mit dem erwarteten und erhalten Sie den entsprechenden Schlüssel .

Update Nr. 2

Unterstützung für Bidi-Karten mit Generika finden Sie in Google Guava und den überarbeiteten 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 Generika wird der Code besser gewartet.

Vineet Reynolds
quelle
23
... und wenn Sie Generika und all das moderne Zeug mögen, hat Google Collections BiMap, wo Sie durch Aufrufen von biMap.inverse (). get (value) Schlüsselübereinstimmungen erhalten können.
Esko
1
Ja, Apache Commons Collections unterstützt keine Generika. Wie Sie bereits erwähnt haben, gibt es jedoch Google-Sammlungen (die ich noch nicht verwende - noch keine Version 1.0), und es gibt die überarbeiteten Commons-Sammlungen mit Unterstützung für Generika. Sie finden dies als Sourceforge-Projekt @ sourceforge.net/projects/collections
Vineet Reynolds
2
Die Google-Sammlungen sind keine überarbeitete Version von Commons-Sammlungen.
whiskeysierra
12
@whiskeysierra: Ich glaube nicht, dass dies (derzeit) jemand sagt.
Huff
2
Apache Collections unterstützt jetzt generics commons.apache.org/proper/commons-collections/javadocs/…
kervin
603

Wenn Ihre Datenstruktur eine Eins-zu-Eins- Zuordnung zwischen Schlüsseln und Werten aufweist, sollten Sie die 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;
}

Bei 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 BiMap auch 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);
Vitalii Fedorenko
quelle
3
Kannst du etwas über die Aufführung sagen? Was wird optimiert? Dies oder BidiMap?
Tasomaniac
Ich habe die gleiche Lösung gedacht, ich habe sie natürlich positiv bewertet, aber ich bezweifle ihre Effizienz, wenn es um wirklich große Sammlungen geht.
Arjacsoh
3
stackoverflow.com/questions/4553624/hashmap-get-put-complexity HashMap ist zeitlich komplexo(1) . Wenn Sie die Werte durchlaufen, wird die Leistung beeinträchtigt. Wenn Sie better performanceeine one-oneBeziehung haben möchten , können Sie another mapwherevalue is a key
veer7
3
Ich empfehle ersetzen .filter(entry -> entry.getValue().equals(value))mit , da keine Aussage über die Fähigkeit gemacht wurde. Darüber hinaus können Sie ersetzen mit.filter(entry ->Objects.equals(entry.getValue(), value))null.map(entry -> entry.getKey()).map(Map.Entry::getKey)
Holger
Ich habe Schwierigkeiten, die <T, E> -Notation zu verstehen, bevor ich <T> getKeysByValue () setze ... was ist der Sinn ... eine andere Art, dies zu tun, ohne das zu verwenden? danke
ponderingdev
76
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 eine eindeutige Zuordnung von Schlüssel zu eindeutigem Wert 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 pflegen

1. Key to value

2. Value to key 

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

Fathah Rehman P.
quelle
19

Ich denke, Ihre Entscheidungen sind

  • Verwenden Sie eine dafür erstellte Kartenimplementierung wie die BiMap aus Google-Sammlungen. Beachten Sie, dass die Google-Sammlungen BiMap sowohl eindeutige Werte als auch Schlüssel erfordern, jedoch eine hohe Leistung in beide Richtungen bieten
  • Verwalten Sie manuell zwei Karten - eine für Schlüssel -> Wert und eine andere Karte für Wert -> Schlüssel
  • Durchlaufen Sie das entrySet()und, um die Schlüssel zu finden, die dem Wert entsprechen. Dies ist die langsamste Methode, da die gesamte Sammlung durchlaufen werden muss, während die beiden anderen Methoden dies nicht erfordern.
Chi
quelle
19

Sie können sowohl das Schlüssel-, Wertepaar als auch dessen Umkehrung 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, konstante Karten zu erstellen, die nur für einige ausgewählte Datensätze funktionieren:

  • Enthält nur 1 bis 1 Paare
  • Der Wertesatz ist vom Schlüsselsatz getrennt (1-> 2, 2-> 3 unterbricht ihn).
Chicowitz
quelle
4
Das ist nicht wirklich richtig. Dies erfordert nicht nur 1-1, sondern auch, dass der Wertesatz vom Schlüsselsatz getrennt ist. Sie können dies nicht auf die bijektive Karte {1 -> 2, 2 -> 3} anwenden: 2 ist sowohl ein Wert als auch ein Schlüssel.
Luis A. Florit
15

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);
    }
}
ABHI
quelle
Ich denke, dies ist ein interessanter Ansatz. Da die Beziehung jedoch 1: 1 sein muss, würde ich HashMap vollständig entfernen und stattdessen die Map <K, V> -Schnittstelle implementieren, um Duplikate von Werten und Schlüsseln zu vermeiden.
Fran Marzoa
11

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

rekursiv
quelle
11

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

wsorenson
quelle
4
Diese Lösung ist schrecklich intensiv, bis zu dem Punkt, an dem sie auf großen HashMaps unpraktisch ist.
Joehot200
10

Verwenden von Java 8:

ftw.forEach((key, value) -> {
    if (value.equals("foo")) {
        System.out.print(key);
    }
});
Phani
quelle
6
value=="foo" das wird nicht funktionieren. equalssollte verwendet werden, um Strings zu vergleichen.
Anton Balaniuc
@Anton, wahr, es sei denn, valuees wurde interniert.
Frododot
9

Wenn Sie die Karte in Ihrem eigenen Code erstellen, versuchen Sie, den Schlüssel und den Wert in der Karte zusammenzufügen:

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

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

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

David Tinker
quelle
3
Clever, aber was ist, wenn zwei oder mehr KeyValue-Objekte denselben Wert enthalten? Welchen Schlüssel soll man wählen?
Vineet Reynolds
2
@ Vineet, ich sehe nicht, wie dieser Ansatz die Frage des OP löst. Was meinten Sie mit "Wenn Sie dann einen Wert haben, haben Sie auch den Schlüssel."?
Qiang Li
9

Ich denke, dies 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 einfügen 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));
Junge
quelle
7

Ich fürchte, Sie müssen nur Ihre Karte iterieren. Am kürzesten konnte ich mir vorstellen:

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
quelle
6
for(int key: hm.keySet()) {
    if(hm.get(key).equals(value)) {
        System.out.println(key); 
    }
}
user309309
quelle
6

Es hört sich so an, als ob Sie am besten über Einträge iterieren können, map.entrySet()da dies map.containsValue()wahrscheinlich sowieso der Fall ist.

Jonas K.
quelle
Ja, genau das macht es. Aber natürlich gibt es true zurück, sobald es einen Wert findet, für den .equals true ist, im Gegensatz zu dem, was OP wahrscheinlich tun muss.
CPerkins
1
Das Durchlaufen von Einträgen kann mit dem Schlüssel zurückgegeben werden, sobald auch ein übereinstimmender Wert gefunden wird. Mehrere Spiele schienen kein Problem zu sein.
Jonas K
6

Für die Android-Entwicklungs-API <19 funktioniert die Eins-zu-Eins-Beziehungslösung von Vitalii Fedorenko nicht, da sie Objects.equalsnicht 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;
}
Die Berga
quelle
Diese Lösung funktioniert bei mir; Entwickelt auch für eine archäologische Android-Version, in meinem Fall, um den Schlüssel eines Google Map-Markers in einer Karte in einem "onMarkerClick" -Ereignis zu erhalten. Das Iterieren des Eintrags funktioniert; Aber die Schlüssel zu iterieren und sie mit get () mit Einträgen abzugleichen und die Ausgabe zu vergleichen, war nicht der Fall.
Toby Wilson
3

Sie können Folgendes 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);
            }
        }
    }
}
Balasubramanian Ganapathi
quelle
Es ist schön, dass Sie nützliche Dinge bereitstellen möchten, aber es sollte keine "Nur-Code" -Antwort sein und der Code selbst sollte auch nicht voller Code-Gerüche sein.
Tom
2

Ja, Sie müssen die Hashmap durchlaufen, es sei denn, Sie implementieren etwas in Anlehnung an diese verschiedenen Antworten. Anstatt mit dem entrySet herumzuspielen, würde ich einfach das keySet () abrufen, über dieses Set iterieren 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 Methode includesValue tut. Sie können diesen Test also einfach alle zusammen überspringen und jedes Mal die Iteration durchführen (oder der Compiler beseitigt die Redundanz bereits, wer weiß).

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

Map<Value, Set<Key>>

Sie können sich mit nicht eindeutigen Schlüssel-> Wertzuordnungen befassen, wenn Sie diese Funktion benötigen (sie entwirren). Das würde sich gut in jede der Lösungen einfügen, die hier mit zwei Karten vorgeschlagen werden.

Carl
quelle
2

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

}
Margus
quelle
Ich denke, diese Antwort könnte durch Hinzufügen einer Erklärung verbessert werden.
Jonathan
2
-1. Ich habe es Stringals Schlüssel und Wert getestet . Wenn ich anrufe, map.add("1", "2"); map.add("1","3");kann ich anrufen map.getKey("2");und abrufen "1", obwohl dies "1"der Schlüssel für ist "3".
Lordo
@Jonathan Die Idee hinter dieser Klasse ist, eine andere HashMap mit den umgekehrten Zuordnungen beizubehalten, damit Sie nicht nur einen Wert von einem Schlüssel abrufen, sondern auch einen Schlüssel von einem Wert abrufen können. Die Klassen T1 und T2 sind etwas verwirrend. Vielleicht nennen Sie sie stattdessen buchstäblich Key & Value? Obwohl ich die Fähigkeit erwarten würde, mehr als einen Wert oder mehr als einen Schlüssel als Gegenleistung zu erhalten, abhängig von den Daten und was Sie wollen. Mit Vorsicht verwenden
Chicowitz
1
@theknightwhosaysni "1" ist nicht mehr der Schlüssel für "2". Dies ist auch die Antwort auf Ihre Frage, der Anruf getValue("1")wird zurückkehren 3.
Jlordo
Sorry jlordo, ich habe mich beim Standard-Hashmap-Verhalten geirrt: Sie haben Recht, dass das Hinzufügen eines neuen Werts für einen Schlüssel den alten Wert ersetzen sollte
Chicowitz
2

In Java8

map.entrySet().stream().filter(entry -> entry.getValue().equals(value))
    .forEach(entry -> System.out.println(entry.getKey()));
user3724331
quelle
2
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;
}
Erstaunliches Indien
quelle
Map <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"));
Erstaunliches Indien
1
Was passiert, wenn mehrere Schlüssel den gleichen Wert haben?
Cà phê đen
Wenn Sie übergeben, dass mehrere Schlüssel denselben Wert haben, erhalten wir den letzten Schlüssel als Ergebnis. Beispiel: A 1, B 1, C 1, D 2 Ausgabe: Wenn wir den 1-Wert übergeben, wird die Ausgabe C
Amazing India
@AmazingIndia Dies ist nicht garantiert und hängt vollständig von der spezifischen Kartenimplementierung ab. HashMap beispielsweise garantiert keine Bestellung, sodass Sie keine Ahnung haben, welche Ausgabe hier zurückgegeben wird.
Niels Doucet
1
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
     */
}
Kanagavelu Sugumar
quelle
1
/**
 * 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;
}
Kanaparthikiran
quelle
1
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);
    }
}
Madhav
quelle
1

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;
   }
}
Jayen
quelle
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, wobei Sie zuerst die Schlüssel in einem Array erhalten, was einige Zeit in Anspruch nehmen kann, und dann eine Schleife ausführen. Ansonsten sollte es für kleinere Karten ok 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)            
}
Manu Bhat
quelle
Und warum sollte jemand diesen Ansatz verwenden? Wie Sie bereits sagten, wäre die Leistung schlechter als bei anderen Ansätzen.
Tom
1

Ich denke, keySet () ist möglicherweise gut geeignet , um die Schlüssel zu finden, die dem Wert zugeordnet sind, und hat einen besseren Codierungsstil als entrySet () .

Ex:

Angenommen, Sie haben eine HashMap- Zuordnung , ArrayList res , einen Wert , zu dem Sie alle Schlüsselzuordnungen finden möchten , und speichern dann die Schlüssel für die res .

Sie können den folgenden Code schreiben:

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

anstatt entrySet () unten zu verwenden:

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

Ich hoffe es hilft :)

FrancisGeek
quelle
map.get(key) == valueDies ist keine gute Idee, wenn Sie die Gleichheit von Objekten überprüfen, da Sie Referenzen vergleichen. .equals()
Objektgleichheit
1

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

Auf diese Weise müssen Sie nicht ständig erstellen / iterieren. Erstellen Sie einfach einmal eine umgekehrte Karte 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;
}
Markymark
quelle
0

Es ist wichtig zu beachten, dass Apache Collections seit dieser Frage generische BidiMaps unterstützt . Einige der am besten bewerteten Antworten sind in diesem Punkt nicht mehr korrekt.

Berücksichtigen Sie für eine serialisierte BidiMap, die auch doppelte Werte unterstützt (1-zu-viele-Szenario), auch MapDB.org .

Kervin
quelle
0
  1. Wenn Sie den Schlüssel vom Wert erhalten möchten, verwenden Sie am besten Bidimap (bidirektionale Karten). Sie können den Schlüssel vom Wert in O (1) -Zeit erhalten.

    Der Nachteil dabei ist jedoch, dass Sie nur eindeutige Schlüssel- und Wertesätze verwenden können.

  2. Es gibt eine Datenstruktur namens Tabelle in Java, die nichts anderes als eine Karte von Karten wie ist

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

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

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

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

Wenn Sie also über T.row (a1) ---> die Karte von -> zurückgeben, erhalten Sie das Keyset für diese zurückgegebene Karte.

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

Vorteile gegenüber dem vorherigen Fall:

  1. Kann mehrere Werte verwenden.
  2. Effizienter bei Verwendung großer Datenmengen.
Batman
quelle