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.

2voto

Jon Polaski Punkte 124

Ich habe dies erstellt, um ein ähnliches Problem zu lösen.

Datenstruktur

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;

public class HashBucket {
    HashMap<Object, ArrayList<Object>> hmap;

    public HashBucket() {
        hmap = new HashMap<Object, ArrayList<Object>>();
    }

    public void add(Object key, Object value) {
        if (hmap.containsKey(key)) {
            ArrayList al = hmap.get(key);
            al.add(value);
        } else {
            ArrayList al = new ArrayList<Object>();
            al.add(value);
            hmap.put(key, al);
        }
    }

    public Iterator getIterator(Object key) {
        ArrayList al = hmap.get(key);
        return hmap.get(key).iterator();

    }

}

Abrufen eines Wertes:

(Hinweis* Das Objekt wird auf den eingefügten Typ zurückgesetzt. In meinem Fall war es mein Ereignisobjekt)

    public Iterator getIterator(Object key) {
        ArrayList al = hmap.get(key);
        if (al != null) {
            return hmap.get(key).iterator();
        } else {
            List<Object> empty = Collections.emptyList();
            return empty.iterator();
        }

    }

Einfügen

Event e1 = new Event();
e1.setName("Bob");
e1.setTitle("Test");
map.add("key",e1);

2voto

bram Punkte 21

Alle Mehrfachschlüssel schlagen wahrscheinlich fehl, da put([key1, key2], val) und get([null, key2]) am Ende die Gleichheit von [key1, key2] und [null, key2] verwenden. Wenn die Backing-Map doesnt enthält Hash-Buckets pro Schlüssel dann Lookups sind wirklich langsam zu.

Ich denke, der Weg zu gehen ist mit einem Index-Dekorator (siehe die key1, key2 Beispiele oben) und wenn die zusätzlichen Index-Schlüssel Eigenschaften des gespeicherten Wertes sind, können Sie die Eigenschaft Namen und Reflexion verwenden, um die Secondairy-Maps zu bauen, wenn Sie put(key, val) und fügen Sie eine zusätzliche Methode get(propertyname, propertyvalue), um diesen Index zu verwenden.

der Rückgabetyp von get(Eigenschaftsname, Eigenschaftswert) könnte eine Sammlung sein, so dass auch nicht eindeutige Schlüssel indiziert werden....

2voto

amjed Punkte 39

Sol: beide Schlüssel annullieren und einen letzten Schlüssel erstellen, diesen als Schlüssel verwenden.

für Schlüsselwerte ,

Verketten Sie ket-1 und key-2 mit einem " , " dazwischen und verwenden Sie dies als ursprünglichen Schlüssel.

Schlüssel = Schlüssel-1 + "," + Schlüssel-2;

myMap.put(Schlüssel,Wert);

in ähnlicher Weise bei der Wiederherstellung von Werten.

3 Stimmen

Was ist mit all den Klassen, die nicht genau als Strings dargestellt werden können?

1 Stimmen

Sie können nicht unterstützen getByKey1 y getByKey2 Operationen mit diesem Ansatz.

1voto

Gadget Punkte 474

Ich habe eine solche Implementierung für mehrere Schlüsselobjekte verwendet. Es erlaubt mir, eine unzählige Anzahl von Schlüsseln für die Karte zu verwenden. Es ist skalierbar und ziemlich einfach. Aber es hat Einschränkungen: Die Schlüssel werden nach der Reihenfolge der Argumente im Konstruktor geordnet und es würde nicht mit 2D-Arrays funktionieren, weil Arrays.equals() verwendet wird. Um dies zu beheben, könnten Sie Arrays.deepEquals() verwenden;

Ich hoffe, es wird Ihnen helfen. Wenn Sie einen Grund kennen, warum es nicht als Lösung für solche Probleme verwendet werden kann - lassen Sie es mich bitte wissen!

public class Test {

    private static Map<InnumerableKey, Object> sampleMap = new HashMap<InnumerableKey, Object>();

    private static class InnumerableKey {

        private final Object[] keyParts;

        private InnumerableKey(Object... keyParts) {
            this.keyParts = keyParts;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (!(o instanceof InnumerableKey)) return false;

            InnumerableKey key = (InnumerableKey) o;

            if (!Arrays.equals(keyParts, key.keyParts)) return false;

            return true;
        }

        @Override
        public int hashCode() {
            return keyParts != null ? Arrays.hashCode(keyParts) : 0;
        }
    }

    public static void main(String... args) {
        boolean keyBoolean = true;
        double keyDouble = 1d;
        Object keyObject = new Object();

        InnumerableKey doubleKey = new InnumerableKey(keyBoolean, keyDouble);
        InnumerableKey tripleKey = new InnumerableKey(keyBoolean, keyDouble, keyObject);

        sampleMap.put(doubleKey, "DOUBLE KEY");
        sampleMap.put(tripleKey, "TRIPLE KEY");

        // prints "DOUBLE KEY"
        System.out.println(sampleMap.get(new InnumerableKey(true, 1d)));
        // prints "TRIPLE KEY"
        System.out.println(sampleMap.get(new InnumerableKey(true, 1d, keyObject)));
        // prints null
        System.out.println(sampleMap.get(new InnumerableKey(keyObject, 1d, true)));
    }
}

1voto

Veeren Jote Punkte 11

Wie wäre es mit so etwas wie diesem:

Seine Aussage besagt, dass die Schlüssel eindeutig sind, so dass es durchaus möglich ist, dieselben Wertobjekte unter verschiedenen Schlüsseln zu speichern, und wenn Sie einen Schlüssel senden, der mit dem besagten Wert übereinstimmt, können wir auf das Wertobjekt zurückgreifen.

Siehe Code unten:

Ein Wert Objektklasse,

    public class Bond {
    public Bond() {
        System.out.println("The Name is Bond... James Bond...");
    }
    private String name;
    public String getName() { return name;}
    public void setName(String name) { this.name = name; }
}

public class HashMapValueTest {

    public static void main(String[] args) {

        String key1 = "A";
        String key2 = "B";
        String key3 = "C";

        Bond bond = new Bond();
        bond.setName("James Bond Mutual Fund");

        Map<String, Bond> bondsById = new HashMap<>();

        bondsById.put(key1, bond);
        bondsById.put(key2, bond);
        bondsById.put(key3, bond);

        bond.setName("Alfred Hitchcock");

        for (Map.Entry<String, Bond> entry : bondsById.entrySet()) {
            System.out.println(entry.getValue().getName());
        }

    }

}

Das Ergebnis ist:

The Name is Bond... James Bond...

Alfred HitchCock

Alfred HitchCock

Alfred HitchCock

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