I am trying to implement a map like
Map<<key1, key2>, List<value>>
Map should contain 2 keys and corresponding value would be a list. I want to add records in same list if alteast one key value is equal For example consider following records
R1[key1, key2]
R2[key1, null/empty] - Key1 is equal
R3[null/empty, key2] - Key2 is equal
R4[key1, key2] - Key1 and Key2 both are equal.
all should be inserted in same list like
Key = <Key1,Key2>
Value = <R1, R2, R3, R4>
I cant use Guava table or commons MulitKeyMap (dont want include whole library just for this) .
I tried to implement a class (which I can use as a key) which will have both key1
and key2
as attribute but implementing a effective hashcode which don't consider key1 and key2 seems bit (or may be a lot) tricky
public class Key {
private int key1;
private int key2;
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
// Cant include key1 and key2 in hashcode
/* result = prime * result + key1;
result = prime * result + key2;*/
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Key other = (Key) obj;
if(key2 and other.key2 both not blank/null){ // pseudo code
if (key2 == other.key2)
return true;
}
if(key1 and other.key1 both not blank/null){ //pseudo code
if (key1 == other.key1)
return true;
}
return true;
}
}
It will work if I use the same hashcode for all but it will impact the performance as I have thousands of records.
EDIT :
I cant use nested Maps like
Map<key1, Map< key2, List<value>>>
As some records might have only one key.
R1[key1, key2] - Have both keys
R2[key1, null/empty] - Key1 is equal
R3[null/empty, key2] - Key1 is missing and key2 is equal
Here R3 dont have key1 and hence cant be inserted in same location as R1 and R2
EDIT 2 :
I also wish to maintain the intertion order.
Maps by definition have 1 key per value.
You could have a map of maps, or your key could be an object with 2 fields, but that's about as close as you can get.
Map of maps:
Map myMap<key, Map<otherkey, value>>
Custom object
public class MapKey {
public Object keyFirstPart;
public Object keySecondPart;
// You'll need to implement equals, hashcode, etc
}
Map myyMap <MapKey, value>
If the HashMap like behaviour is required, I'd create two Maps, and do the magic in handling the collections (also, I'd recommend using Sets for this...):
public class MyMap<K1, K2, V> {
Map<K1, Collection<V>> map1;
Map<K2, Collection<V>> map2;
//have to add to both lists
put(K1 k1, K2 k2, V v) {
addToCollection(map1, k1, v);
addToCollection(map2, k2, v);
}
//notice T param
<T> void addToCollection(Map<T, Collection<V>> map, T key, V value ) {
Collection<V> collection= map.get(key);
if(collection==null) {
collection= new HashSet<V>();
map.put(key, collection);
}
collection.add(value );
}
public Collection<V> get(K1 k1, K2 k2) {
Collection<V> toReturn = new HashSet<V>();
Collection<V> coll1 = map1.get(k1);
if(coll1!=null) {
toReturn.addAll(coll1);
}
Collection<V> coll2 = map2.get(k2);
if(coll2!=null) {
toReturn.addAll(coll2);
}
return toReturn;
}
}
Use a TreeMap instead, this way you can make use a custom comparator for your CustomKey class instead of a Hashcode.
TreeMap<CustomKey, List<value>> map = new TreeMap<CustomKey, List<value>>(myComparator);
eta: instead of creating a comparator class you can make the CustomKey class implement Comparable
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With