Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Map with multiple keys [duplicate]

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.

like image 552
Ajinkya Avatar asked Oct 04 '13 08:10

Ajinkya


3 Answers

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>
like image 144
GordonM Avatar answered Sep 23 '22 09:09

GordonM


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;
  }
}
like image 35
ppeterka Avatar answered Sep 25 '22 09:09

ppeterka


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

like image 35
tom Avatar answered Sep 22 '22 09:09

tom