[ACCEPTED]-Using two (or more) objects as a HashMap key-map

Accepted answer
Score: 14

You key must implement the hashCode and 2 equals. If it is a SortedMap, it must also implements 1 the Comparable interface

public class MyKey implements Comparable<MyKey>
{
private Integer i;
private String s;
public MyKey(Integer i,String s)
{
this.i=i;
this.s=s;
}

public Integer getI() { return i;}
public String getS() { return s;}

@Override
public int hashcode()
{
return i.hashcode()+31*s.hashcode();
}

@Override
public boolean equals(Object o)
{
if(o==this) return true;
if(o==null || !(o instanceof MyKey)) return false;
MyKey cp= MyKey.class.cast(o);
return i.equals(cp.i) && s.equals(cp.s);
    }

   public int compareTo(MyKey cp)
     {
     if(cp==this) return 0;
     int i= i.compareTo(cp.i);
     if(i!=0) return i;
     return s.compareTo(cp.s);
     }


 @Override
    public String toString()
       {
       return "("+i+";"+s+")";
       }

    }

public Map<MyKey,String> map= new HashMap<MyKey,String>();
map.put(new MyKey(1,"Hello"),"world");
Score: 10

I tend to use a list

map.put(Arrays.asList(keyClass, keyString), value)

0

Score: 4

The easiest way that I know of is to make 9 a wrapper class and override hashmap and 8 equals. For instance:

public class KeyClass {

    private String element1;
    private String element2;

    //boilerplate code here

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof KeyClass) {
            return element1.equals(((KeyClass)obj).element1) &&
                element2.equals(((KeyClass)obj).element2);
        }
        return false;
    }

    @Override
    public int hashCode() {
        return (element1 + element2).hashcode();
    }
}

OF course, I would 7 recommend using a StringBuilder and whatever 6 else, but this way you have overridden the 5 equals and hashcode, thereby allowing a 4 hash and equality check on your multiple 3 keys.

Also, I would recommend making the 2 objects immutable (not editable) for safety's 1 sake, but that is purely preference.

Score: 3

Apache Commons Collections has a multikey 2 map which might do the trick for you:

https://commons.apache.org/proper/commons-collections/apidocs/org/apache/commons/collections4/keyvalue/MultiKey.html

It 1 looks like it will handle up to 5 "keys".

Score: 2

Do you mean that the object will be keyed 6 by two keys, or rather a key which consists 5 of two things.

If you want the first case. That 4 is, an objected keyed by two keys, say a 3 class or an object, you need to use two 2 maps.

Map<Key1, value>

Map<Key2, value>

In the second case you need a map of 1 maps, so:

Map<Key1, Map<Key2, value>>
Score: 1

You could create a holder class that contains 3 the class and string that you want as the 2 keys.

public class Key {

    public MyClass key_class;
    public String key_string;

    public Key(){
        key_class = new MyClass();
        key_string = "";
    }

}

Probably not the best solution, but 1 a possibility.

Score: 0

There are a few places where people suggest 28 creating a "Key" class containing the others, I 27 totally agree. Just thought I'd add a helpful 26 hint.

If you use eclipse or netbeans, they 25 have a nice option--you can tell Eclipse 24 to create equals and hashcode methods based 23 on one or more members. So you just select 22 the member (or members) you want to retrieve 21 by and NB creates most of the code you'd 20 need to write for you.

of course when I just 19 want to retrieve by one object, I often 18 just delegate the hashcode and equals methods 17 to that object (delegating equals might 16 be problematic because it would mean that 15 one of your "Key holder" classes would be 14 equal to the object that is it's key, but 13 that's pretty easily fixed (and wouldn't 12 usually effect anything anyway)

so off the 11 top of my head:

class KeyHolder {
    public final String key;
    public final Object storeMe;

    public KeyHolder(String key, Object storeMe) {
        this.key=key;
        this.storeMe=storeMe;
    }

    public equals(Object o) {
        return (o instanceof KeyHolder && ((KeyHolder)o).key.equals(key));
    }

    public hashcode() {
        return key.hashCode();
    }
}

That's all there is to it, and 10 eclipse will do the last two for you if 9 you ask it to.

By the way, I know that I 8 have public members, a public final member 7 is exactly the same thing as having a getter--not 6 really a terrible idea. I'm starting to 5 use this pattern on small utility classes 4 like this a lot more lately. If the member 3 wasn't final, it would be worse because 2 it would be like having a setter (Something 1 I try to avoid these days).

Score: 0

One can solve this issue using apache's 2 commons collection lib's MultiKey class. Here is a simple 1 example:

import org.apache.commons.collections.keyvalue.MultiKey;

HashMap map = new HashMap();
MultiKey multiKey = new MultiKey(key1, key2);

map.put(multikey,value);

//to get 
map.get(new MultiKey(key1,key2)); 

More Related questions