Reputation: 4558
I have a problem which is about creating a map with 2 different keys. The keys would possibly be of the same type though. The question is similar to this,
How to create a map with 2 key value
But it does also differ since the keys does not need to be set at the same time. So more concretely, the properties should be that,
1) One of the keys are sufficient to get a value from the map.
2) In case one of the keys are set, the other key can be set given the first key.
3) The user should not need to bother what key it uses (the first or the second)
The theory is to implement this using 2 maps as this,
public MultiKeyMap<K1, K2, V> {
private HashMap<K1 , V> map1;
private HashMap<K2, V> map2;
public MultiKeyMap(){
map1 = new HashMap<K1, V>();
map2 = new HashMap<K2, V>();
}
public void put(K1 k1, V v){
?
}
public void get(K1 k1, V v){
?
}
public void put(K1 k1, K2 k2, V v){
map1.put(k1, v);
map2.put(k2, v);
}
However, when I get to the part with one value I get confused, The keys may both be of the same type (eg. String), so how would I make a difference between the values. One alternative would be, that in case the second value is of the same type as the first, then I just add it to the first map using duplicate values. Would this be a good option? My point is, this would affect the syntax since the user would still just call myMap.get(myKey)
, further, I would also guess this would be an optimization since I only need one map. I would just need a flag like boolean secondKeyAvail = false
. I should be able to handle (2) by myself. This is more to give context and motivate why this question is not the same as the linked one.
EDIT:
Due to some of the comments I will try to clarify a bit. This is the scenario. Before I need to read the map I will encounter one of keys (always the same one). However, this key object may sometimes not be accessible at the time I need to read the map. I will then have a default value which is not added to the map. However, in this case I will have the second key, and if this happen I would have been able to set the second key using the first key. However, if the key is of the same type I will not know if I have the K1 key or the K2 key with the call (myMap.get(myKey)).
Upvotes: 2
Views: 774
Reputation: 156459
How important is type safety on the keys? If you have separate put
methods for each type, and then the types are the same, your compiler won't know which version to call. If you just use one method, you can't restrict the type to be "K1
or K2
". But if you were willing to have the get
and put
methods take an Object
for the keys, or require the user to use the two-key put
method, then you could just use a single backing HashMap that doesn't care what the key type is.
public MultiKeyMap<K1, K2, V> {
private HashMap<Object, V> map;
public MultiKeyMap(){
map = new HashMap<Object, V>();
}
public void put(Object key, V v){
map.put(key, v);
}
public void get(Object key, V v){
return map.get(key);
}
public void put(K1 k1, K2 k2, V v){
if(!map.containsKey(k1) && !map.containsKey(k2)) {
map.put(k1, v);
map.put(k2, v);
}
}
It's worth noting that the real HashMap.get()
method takes an Object
as its key, anyway.
Upvotes: 1
Reputation: 2179
Following code implements API that lets you to put value either by K1 or by K2, to get value by any key and to propagate one key to another
public class Tuple<X, Y> {
public final X x;
public final Y y;
public Tuple(X x, Y y) {
this.x = x;
this.y = y;
}
}
public MultiKeyMap<K1, K2, V> {
private HashMap<Tuple<K1, K2> , V> map;
public MultiKeyMap(){
map = new HashMap<Tuple<K1, K2>, V>();
}
public void putByK1(K1 k1, V v){
map.put(new Tuple(k1, null), v);
}
public void putByK2(K2 k2, V v){
map.put(new Tuple(null, k2), v);
}
public void getByK1(K1 k1){
map.get(new Tuple(k1, null));
}
public void getByK2(K2 k2){
map.get(new Tuple(null, k2));
}
public void put(K1 k1, K2 k2, V v){
map.put(new Tuple(null, k2), v);
map.put(new Tuple(k1, null), v);
}
public void propagateK1(K1 k1, K2 k2) {
map.put(new Tuple(null, k2), get(k1));
}
public void propagateK2(K2 k2, K1 k1) {
map.put(new Tuple(k1, null), get(k2));
}
}
Upvotes: 0