Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Collection with 2 keys

I want to implement a HashMap with a key with 2 components. Ex.

Pseudocode:

Key = <Component1, Component2>
CollName<Key, Val> coll = new CollName<Key, Val>;

How can I implement this in Java, considering speed and size of the Collection. Thanks :D

like image 500
John Bautista Avatar asked Feb 14 '11 06:02

John Bautista


2 Answers

You need a helper (composite key) class that holds your two keys

public class CompositeKey<... , ...> {
   ... component1;
   ... component2;

   // getter , setter, ...

   // equals

  // hashcode()
}

and then you can use it as key:

CompositeKey cKey = new CompositeKey(1,2);
Map x.put(cKey,val);

It is very important here to implement equals() and hashCode() in a good fashion. Most IDEs can help you here. Important is for the hashCode that it returns a "unique" value in order to prevent hash collisions of the keys (i.e. returning a constant value is the worst case, as all values would end up in the same bucket). Many implementations of hashcode do something along

hashcode = component1.hashCode() + 37* component2.hashCode();

If you want more details, dig out any CS book that talks about hashing algorithms.

If you want to use that for persistence, also have a look at this blog post.

like image 90
Heiko Rupp Avatar answered Oct 24 '22 17:10

Heiko Rupp


You can't directly create a Map with two keys, however you can combine the two.

The simplest method is to serialize them to a string and combine them.

String key = obj1.toString() + "-" + obj2.toString();
myMap.put( key, myValue );

presuming the objects can easily be serialized to a string that would be unique.

If this is not the case, then creating a wrapper object is your best option. You would need to define an object that overrides the equals() and hashCode() method.

As a rough example

class CombinedKey{
    private MyClass object1; 
    private MyClass object2;

    public CombinedKey( MyClass object1, MyClass object2 ){
        this.object1 = object1;
        this.object2 = object2;
    }
    public int hashCode(){ 
        return object1.hashCode() + object2.hashCode();
    }

    @Override
    public Boolean equals( Object otherObject ){
        if( otherObject == null || otherObject.getObject1() == null ) return false;
        return object1.equals( otherObject.getObject1() ) && object2.equals( otherObject.getObject2();
    }

    public MyClass getObject1() { return object1; }
    public MyClass getObject2() { return object2; }

}

(You might also want to consider using Generics to define this class so it can be reused in other scenarios)

Usage:

Map<CombinedKey, Object> myMap = new HashMap<CombinedKey, Object>();
myMap.put( new CombinedKey(obj1, obj2), value );
like image 44
James Davies Avatar answered Oct 24 '22 18:10

James Davies