185 Stimmen

Wie implementiert man eine Karte mit mehreren Schlüsseln?

Ich brauche eine Datenstruktur, die sich wie eine Map verhält, aber mehrere (unterschiedlich typisierte) Schlüssel für den Zugriff auf ihre Werte verwendet.
(Lassen Sie uns nicht zu allgemein sein, sagen wir zwei Tasten)

Die Einzigartigkeit der Schlüssel ist garantiert.

Etwa so:

MyMap<K1,K2,V> ...

Mit Methoden wie:

getByKey1(K1 key)...
getByKey2(K2 key)...
containsKey1(K1 key)...
containsKey2(K2 key)...

Haben Sie irgendwelche Vorschläge?

Das Einzige, was mir einfällt, ist:
Schreiben Sie eine Klasse, die intern zwei Maps verwendet.

EDIT Einige Leute schlagen mir vor, eine Tupel , a Paar oder ähnlich als Schlüssel für Java's Map, aber das würde nicht funktionieren für mich:
Ich muss, wie oben geschrieben, in der Lage sein, Werte nur nach einem der beiden angegebenen Schlüssel zu suchen.
Maps verwenden Hash-Codes von Schlüsseln und überprüfen deren Gleichheit.

0 Stimmen

Ich bin erstaunt, dass diese Frage trotz fast 200.000 Aufrufen noch nicht verbessert wurde.

112voto

Jeremy Huiskamp Punkte 5086

Zwei Karten. Eine Map<K1, V> und einer Map<K2, V> . Wenn Sie eine einzige Schnittstelle haben müssen, schreiben Sie eine Wrapper-Klasse, die diese Methoden implementiert.

7 Stimmen

Äh, ja, das ist genau das, was Sie vorgeschlagen haben. Zwei Maps ist der richtige Weg. Um auf eine beliebige Anzahl von Schlüsseln zu erweitern, haben Sie eine Methode wie getByKey(MetaKey mk, Object k) und dann eine Map<MetaKey, Map<Object, V>> intern.

0 Stimmen

Schließen Sie die beiden Karten immer in eine Klasse ein!

46voto

Nathan Feger Punkte 18486

Commons-Collections bietet genau das, was Sie suchen: https://commons.apache.org/proper/commons-collections/apidocs/

Es sieht so aus, als ob jetzt die Commons-Sammlungen eingegeben werden.

Eine maschinengeschriebene Fassung ist zu finden unter: https://github.com/megamattron/collections-generic

Dies wird genau Ihren Anwendungsfall unterstützen:

 MultiKeyMap<k1,k2,...,kn,v> multiMap = ??

1 Stimmen

Ich glaube, mit Generika (mit der alternativen Sammlungen Lib) ist nur möglich, wenn alle Ihre Schlüssel vom gleichen Typ sind. MultiKeyMap<k1,k2,v> lässt sich einfach nicht kompilieren.

83 Stimmen

Ich denke, diese Antwort ist falsch. Es gibt keine Möglichkeit, einen Wert von commons MultiKeyMap nur durch die Verwendung eines zweiten Schlüssels zu erhalten. Sie müssen immer sowohl key1 als auch key2 angeben. Warum hat diese Antwort so viele "up votes" erhalten?

1 Stimmen

@Zombies, Sie haben mich nicht verstanden. Es gibt keine Möglichkeit, das ursprüngliche Problem mit der MultiKeyMap-Klasse von Commons-Collections zu lösen. Wenn es eine gibt, erklären Sie sie bitte.

44voto

Logan Capaldo Punkte 38523

Ich schlage immer noch die 2-Karten-Lösung vor, aber mit einem Tweest

Map<K2, K1> m2;
Map<K1, V>  m1;

Mit diesem Schema können Sie eine beliebige Anzahl von Schlüssel-"Aliasen" haben.

Außerdem können Sie den Wert über einen beliebigen Schlüssel aktualisieren, ohne dass die Maps nicht mehr synchronisiert werden.

20 Stimmen

Das einzige Problem dabei ist, dass Sie kein K1 haben.

1 Stimmen

Milhous: Ja, das ist ein Problem bei dieser Lösung.

0 Stimmen

Das Aktualisieren ist auch in meiner Antwort ein Problem. Z. B. speichern Sie den Wert "1" mit K1=A und K2=B, dann speichern Sie den Wert "1" mit K1=C und K2=D. Nun versuchen Sie, den Wert = "2" zu setzen, wobei K1=A ist. Woher wissen Sie, welcher K2 zu verwenden ist? Logan, deine Lösung funktioniert, aber du solltest vielleicht auch eine Map<K1, K2> behalten. Das ist wahrscheinlich ein bisschen theoretisch, da es nicht so aussieht, als würde die ursprüngliche Frage Aktualisierungen berücksichtigen.

40voto

Tombart Punkte 27954

Eine andere Lösung ist die Verwendung von Guava von Google

import com.google.common.collect.Table;
import com.google.common.collect.HashBasedTable;

Table<String, String, Integer> table = HashBasedTable.create();

Die Verwendung ist wirklich einfach:

String row = "a";
String column = "b";
int value = 1;

if (!table.contains(row, column)) {
    table.put(row, column, value);
}

System.out.println("value = " + table.get(row, column));

Die Methode HashBasedTable.create() macht im Grunde so etwas wie das hier:

Table<String, String, Integer> table = Tables.newCustomTable(
        Maps.<String, Map<String, Integer>>newHashMap(),
        new Supplier<Map<String, Integer>>() {
    public Map<String, Integer> get() {
        return Maps.newHashMap();
    }
});

Wenn Sie versuchen, einige benutzerdefinierte Karten zu erstellen, sollten Sie sich für die zweite Option entscheiden (wie @Karatheodory vorschlägt), ansonsten sollten Sie mit der ersten Option zurechtkommen.

2 Stimmen

Im obigen Beispiel wäre es besser, die Standardfabrik von Guava für Hash-basierte Tabellen zu verwenden: HashBasedTable.create() . Die newCustomTable() Methode sollte nur für wirklich benutzerdefinierte Maps verwendet werden.

21voto

Guigon Punkte 225

Wie wäre es, wenn Sie die folgende "Key"-Klasse deklarieren:

public class Key {
   public Object key1, key2, ..., keyN;

   public Key(Object key1, Object key2, ..., Object keyN) {
      this.key1 = key1;
      this.key2 = key2;
      ...
      this.keyN = keyN;
   }

   @Override   
   public boolean equals(Object obj) {
      if (!(obj instanceof Key))
        return false;
      Key ref = (Key) obj;
      return this.key1.equals(ref.key1) && 
          this.key2.equals(ref.key2) &&
          ...
          this.keyN.equals(ref.keyN)
   }

    @Override
    public int hashCode() {
        return key1.hashCode() ^ key2.hashCode() ^ 
            ... ^ keyN.hashCode();
    }

}

Deklarieren der Karte

Map<Key, Double> map = new HashMap<Key,Double>();

Deklaration des Schlüsselobjekts

Key key = new Key(key1, key2, ..., keyN)

Füllen der Karte

map.put(key, new Double(0))

Abrufen des Objekts aus der Karte

Double result = map.get(key);

1 Stimmen

Dieser ansatz ist leistungsfähiger, als es auf den ersten blick den anschein hat. man kann sogar einfach eine Object[] als Schlüssel

0 Stimmen

Sind die Ellipsen-Argumente tatsächlich Ellipsen? Oder geben Sie nur an, dass der Benutzer 1, 2 oder bis zu N angeben soll, wenn er die Klasse erstellt. Mit anderen Worten, es handelt sich nicht um eine Klasse, die eine variable Anzahl von Schlüsseln verarbeiten soll, oder?

3 Stimmen

Der Auftraggeber möchte die Schlüssel nicht kombinieren, sondern beide getrennt verwenden.

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