Victor2748
Victor2748

Reputation: 4199

Java Map with multiple keys

I need to create a map, with 3 columns: 2 keys, and 1 value. So each value will contain 2 keys of different classtypes, and can be fetched by using either one. But my problem is that HashMap/Map supports only 1 key, and 1 value. Is there a way to create something like Map<Key1, Key2, Value> instead of Map<Key, Value>? so Value can be fetched by either using its Key1 or Key2.

I apologize if it is a duplicate or a bad question, but I couldn't find a similar one on Stack Overflow.

P.S: I don't want to create 2 maps: Map<Key1, Value> and Map<Key2, Value> nor creating nested maps I am looking for a multikey table, just one like above.

Upvotes: 1

Views: 6631

Answers (5)

Jey Ganesh
Jey Ganesh

Reputation: 38

Take a look at guava's Table collection that can be used in your context

http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/Table.html

 Table<String,String,String> ==> Map<String,Map<String,String>>

Upvotes: 0

Robin Varghese
Robin Varghese

Reputation: 475

Have you looked into Apache Commons Collection multi map interface? https://commons.apache.org/proper/commons-collections/javadocs/api-3.2.1/org/apache/commons/collections/MultiMap.html

Upvotes: 0

Bohemian
Bohemian

Reputation: 424973

Just store the value twice:

Map<Object, Value> map = new HashMap<>();
map.put(key1, someValue);
map.put(key2, someValue);

The thing is, it doesn't really matter what type the key is, so use a generic bound that allows both key types - Object is fine.

Note that the parameter type of Map#get() method is just Object anyway, so from a look-up perspective there's no value in having separate maps (the type of the key is only relevant for put()).

Upvotes: 1

Ruslan
Ruslan

Reputation: 14620

Write class with your requirements by yourself:

import java.util.HashMap;
import java.util.Map;

public class MMap<Key, OtherKey, Value> {

    private final Map<Key, Value> map = new HashMap<>();

    private final Map<OtherKey, Value> otherMap = new HashMap<>();

    public void put(Key key, OtherKey otherKey, Value value) {
        if (key != null) { // you can change this, if you want accept null.
            map.put(key, value);
        }
        if (otherKey != null) {
            otherMap.put(otherKey, value);
        }
    }

    public Value get(Key key, OtherKey otherKey) {
        if (map.containsKey(key) && otherMap.containsKey(otherKey)) {
            if (map.get(key).equals(otherMap.get(otherKey))) {
                return map.get(key);
            } else {
                throw new AssertionError("Collision. Implement your logic.");
            }
        } else if (map.containsKey(key)) {
            return map.get(key);
        } else if (otherMap.containsKey(otherKey)) {
            return otherMap.get(otherKey);
        } else {
            return null; // or some optional.
        }
    }

    public Value getByKey(Key key) {
        return get(key, null);
    }

    public Value getByOtherKey(OtherKey otherKey) {
        return get(null, otherKey);
    }
}

Upvotes: 2

cogitos
cogitos

Reputation: 336

You're probably going to have to write a custom implementation of a map-like class to implement this. I agree with @William Price above, the easiest implementation will be to simply encapsulate two Map instances. Be careful using the Map interface, as they rely on equals() and hashCode() for key identity, which you intend to break in your contract.

Upvotes: 2

Related Questions