Reputation: 4199
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
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
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
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
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
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