529 Stimmen

Java Hashmap: So erhalten Sie den Schlüssel vom Wert?

Wenn ich den Wert "foo" habe und eine HashMap ftw, für die ftw.containsValue("foo") true zurückgibt, wie kann ich den entsprechenden Schlüssel erhalten? Muss ich durch die HashMap schleifen? Wie ist der beste Weg, das zu tun?

663voto

Vitalii Fedorenko Punkte 103468

Wenn Ihre Datenstruktur eine Viele-zu-Eins-Zuordnung zwischen Schlüsseln und Werten aufweist, sollten Sie über Einträge iterieren und alle geeigneten Schlüssel auswählen:

public static  Set getKeysByValue(Map map, E value) {
    Set keys = new HashSet();
    for (Entry 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 getKeyByValue(Map map, E value) {
    for (Entry entry : map.entrySet()) {
        if (Objects.equals(value, entry.getValue())) {
            return entry.getKey();
        }
    }
    return null;
}

In Java 8:

public static  Set getKeysByValue(Map map, E value) {
    return map.entrySet()
              .stream()
              .filter(entry -> Objects.equals(entry.getValue(), value))
              .map(Map.Entry::getKey)
              .collect(Collectors.toSet());
}

Auch für Guava-Benutzer kann BiMap nützlich sein. Zum Beispiel:

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

4 Stimmen

Können Sie etwas zur Leistung sagen? Was wird optimierter sein? Dies oder BidiMap?

0 Stimmen

Ich habe dieselbe Lösung in Betracht gezogen, ich habe sie natürlich hochgestuft, aber ich zweifle an ihrer Effizienz bei wirklich großen Sammlungen.

3 Stimmen

stackoverflow.com/questions/4553624/hashmap-get-put-complexi‌​ty HashMap hat eine Zeitkomplexität von o(1). Wenn Sie über die Werte iterieren, wird dies die Leistung beeinträchtigen. Wenn Sie eine bessere Leistung wollen und eine eins-zu-eins Beziehung haben, können Sie eine andere Map verwenden, in der der Wert ein Schlüssel ist

241voto

Vineet Reynolds Punkte 74302

Wenn Sie sich dafür entscheiden, anstelle des Standard-Java-Collections-Frameworks die Commons Collections-Bibliothek zu verwenden, können Sie dies problemlos erreichen.

Das BidiMap-Interface in der Collections-Bibliothek ist eine bidirektionale Abbildung, die es Ihnen ermöglicht, einen Schlüssel auf einen Wert abzubilden (wie normale Abbildungen) und auch einen Wert auf einen Schlüssel abzubilden, sodass Sie Abfragen in beide Richtungen durchführen können. Das Abrufen eines Schlüssels für einen Wert wird durch die Methode getKey() unterstützt.

Es gibt jedoch einen Haken, bidirektionale Abbildungen können keine mehreren Werte auf Schlüssel abbilden, und daher können Sie bidirektionale Abbildungen nicht verwenden, es sei denn, Ihr Datensatz hat 1:1-Zuordnungen zwischen Schlüsseln und Werten.


Wenn Sie auf die Java Collections-API vertrauen möchten, müssen Sie sicherstellen, dass die 1:1-Beziehung zwischen Schlüsseln und Werten beim Einfügen des Werts in die Abbildung besteht. Das ist leichter gesagt als getan.

Sobald Sie das sicherstellen können, verwenden Sie die Methode [entrySet()](https://docs.oracle.com/javase/7/docs/api/java/util/Map.html#entrySet()), um die Menge der Einträge (Abbildungen) in der Map zu erhalten. Sobald Sie die Menge erhalten haben, deren Typ Map.Entry ist, durchlaufen Sie die Einträge, vergleichen den [gespeicherten Wert](https://docs.oracle.com/javase/7/docs/api/java/util/Map.Entry.html#getValue()) mit dem erwarteten und erhalten den entsprechenden Schlüssel.


Unterstützung für bidirektionale Abbildungen mit Generics finden Sie in Google Guava und den überarbeiteten Commons-Collections-Bibliotheken (letztere ist kein Apache-Projekt). Danke an Esko für den Hinweis auf den fehlenden generischen Support in Apache Commons Collections. Die Verwendung von Sammlungen mit Generics führt zu wartungsfähigerem Code.


Seit Version 4.0 unterstützt die offizielle Apache Commons Collections™-Bibliothek Generics.

Sehen Sie sich die Zusammenfassungsseite des Pakets "org.apache.commons.collections4.bidimap" für die Liste der verfügbaren Implementierungen des BidiMap, OrderedBidiMap und SortedBidiMap Interfaces an, die jetzt Java-Generics unterstützen.

26 Stimmen

...und wenn Sie Generics und all diesen modernen Kram mögen, hat Google Collections eine BiMap, in der Sie den Schlüssel für den angegebenen Wert erhalten können, indem Sie biMap.inverse().get(value) aufrufen.

1 Stimmen

Ja, Apache Commons Collections unterstützt keine Generics. Es gibt jedoch Google Collections, wie Sie bereits angemerkt haben (den ich noch nicht verwende - noch kein 1.0 Release), und es gibt die refaktorierte Commons-Collections mit Unterstützung für Generics. Sie finden dieses als Sourceforge-Projekt unter sourceforge.net/projects/collections

2 Stimmen

Die Google-Sammlungen sind nicht eine refaktorierte Version von Commons-Collections.

89voto

Fathah Rehman P Punkte 7871
public class NewClass1 {

    public static void main(String[] args) {
       Map testMap = new HashMap();
        testMap.put(10, "a");
        testMap.put(20, "b");
        testMap.put(30, "c");
        testMap.put(40, "d");
        for (Entry entry : testMap.entrySet()) {
            if (entry.getValue().equals("c")) {
                System.out.println(entry.getKey());
            }
        }
    }
}

Einige zusätzliche Informationen... Möglicherweise nützlich für dich

Die obige Methode ist möglicherweise nicht gut, wenn deine Hashmap wirklich groß ist. Wenn deine Hashmap eine eindeutige Zuordnung von Schlüssel zu Wert enthält, kannst du eine weitere Hashmap pflegen, die die Zuordnung von Wert zu Schlüssel enthält.

Du musst also zwei Hashmaps pflegen

1. Schlüssel zu Wert

2. Wert zu Schlüssel

In diesem Fall kannst du die zweite Hashmap verwenden, um den Schlüssel zu erhalten.

27voto

Chicowitz Punkte 5539

Sie könnten sowohl das Schlüssel-Wert-Paar als auch sein Inverses in Ihre Kartenstruktur einfügen

map.put("derSchlüssel", "derWert");
map.put("derWert", "derSchlüssel");

Die Verwendung von map.get("derWert") gibt dann "derSchlüssel" zurück.

Es ist ein schneller und schmutziger Weg, auf dem ich konstante Karten erstellt habe, die nur für einige wenige Datensätze funktionieren:

  • Enthält nur 1-zu-1-Paare
  • Menge der Werte ist disjunkt von der Menge der Schlüssel (1->2, 2->3 bricht es)

4 Stimmen

Dies ist nicht wirklich korrekt. Dies erfordert nicht nur 1-1, sondern auch, dass die Menge der Werte disjunkt von der Menge der Schlüssel ist. Dies lässt sich nicht auf die bijektive Abbildung {1 -> 2, 2 -> 3} anwenden: 2 ist sowohl ein Wert als auch ein Schlüssel.

23voto

Chi Punkte 21806

Ich denke, deine Möglichkeiten sind

  • Verwenden einer für dieses Zweckes entwickelten Kartenimplementierung, wie z.B. die BiMap von Google Collections. Beachten Sie, dass die BiMap von Google Collections die Eindeutigkeit der Werte sowie der Schlüssel erfordert, aber in beide Richtungen eine hohe Leistung bietet.
  • Zwei Karten manuell pflegen - eine für Schlüssel -> Wert und eine andere Karte für Wert -> Schlüssel.
  • Durchlaufen des entrySet() und Suchen der Schlüssel, die mit dem Wert übereinstimmen. Dies ist die langsamste Methode, da sie erfordert, dass die gesamte Sammlung durchlaufen wird, während die anderen beiden Methoden dies nicht erfordern.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X