1

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.

5
  • 1
    possible duplicate of Java: Is there a data structure that works like a multimap but accepts duplicate keys? Commented Sep 29, 2014 at 22:37
  • I don't believe there is an existing data structure which will do what you want. You would have to write your own. Commented Sep 29, 2014 at 22:43
  • Guava's Multimap is essentially a Map<T, Map<K, V>> you can also check out the BiMap. Commented Sep 29, 2014 at 22:43
  • @Mr.Polywhirl: I think you're referring to Guava's Table, not Multimap. Commented Sep 29, 2014 at 22:44
  • You might need to elaborate why two maps is not an acceptable solution. Without further details, encapsulating two such maps in a new class is how I'd naively solve that problem. Commented Sep 29, 2014 at 22:45

5 Answers 5

2

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.

Sign up to request clarification or add additional context in comments.

Comments

2

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);
    }
}

Comments

1

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()).

4 Comments

Ok, I'll just do 2 maps. Thanks
As long as one doesn't need type safety of the specific Key1 and Key2 generic type variables, this is a good solution.
@victor I would not use two maps. Having to look up both maps is a waste of your time, code and CPU cycles, AFAICT without benefit. It's the value type of a map that matters. Note that the parameter type of the get method of Map is Object!
The type of the map key might matter if one expects to use some APIs like keySet() or entrySet(), but without a stated use case it's hard to say.
0

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

Comments

0

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>>

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.