I think my question is similar to this one: How to implement a Map with multiple keys? but with an important difference. In that question (if my understanding of it is correct, please let me know if it isn't), the keys were supposed to always be unique. I want to have a Map in the form: MyMap where the keys aren't necessarily unique. If that doesn't make sense, I basically want a 2 dimensional array, but rather than refering to elements by coordinates, I want to refer to them by pairs of objects.
Anyone have any ideas as to either a library where this works or a good way to implement this myself? As far as libraries go, I've looked at Apache Commons and Guava, neither seem to have what I want.
However, none of the existing Java core Map implementations allow a Map to handle multiple values for a single key. As we can see, if we try to insert two values for the same key, the second value will be stored, while the first one will be dropped.
We can also use Apache Commons Collection, which provides an efficient map implementation MultiKeyMap that maps multiple keys to a value. MultiKeyMap provides get, containsKey, put, and remove for individual keys.
Java HashMap stores references to Objects. If you store same object with two different keys, the keys will point to the same value.
You can't have an hash map with multiple keys, but you can have an object that takes multiple parameters as the key.
The Table data structure in Guava seems to meet you requirement of refering to a value by a pair of objects.
I hope this answer won't be seen as a rant, but as far as I could understand, you want to use a library for something that you can achieve in a trivial way using a jdk out of the box.
Anyway, you mentioned that you want to access elements using a pair of objects. You could create a class that will hold the keys, such as
public class Pair {
// string represntation of an object
private final String x;
private final String y;
// ctor, getters...
public int hashcode() {...}
public boolean equals(Object other) {...}
}
The hashcode
method will generate the hashcode for all comprising elements (in this case, two, x
and y
in your case, but can be easily extended to support an arbitrary number of elements), and two keys will be the same if they have the same values for x
and y
. If your pair elements are not simple strings, it is trivial to derive a string representation of almost any object (provide a decent implementation of the toString
method, for instance).
The idea is to have a unique string representation for each element in the pair.
Of course, generating solid hashcodes is not trivial, so an excellent option isto use Strings. To generate a hashcode, you would simply append the string representations of your pair objects:
public int hashcode() {
return ('x' + x + ":y" + y).hashcode();
}
Be sure to provide some separator. Otherwise, for values such as x=ab, y=b
, and x=a, y=bb
, you'll get the same hashcode, even if the objects are completely different.
And equality is as trivial as inspecting the value of the elements in the pair:
public boolean equals(Object other) {
// if other is not null and is an instance of Pair
final Pair otherPair = (Pair)other;
return this.x.equals(otherPair.x) && this.y.equals(otherPair.y);
}
So, now you could use your Pair
class in a map, such as in:
final Map<Pair, Whatever> map = new Hashmap<Pair, Whatever>();
// ...
Basicaly, a hashmap works by using the hashcode of the keys to determine in which bucket the value should be allocated. If two keys have the same hashcode, then the equals method will be used to determine if a collision just occurred, or if it's just the same key.
If you want to use your Pair
class in a TreeMap
, you would have to implement the compareTo
method, or provide your own Comparator
when instantiating such a map. TreeMap
implementations rely on the result of the compareTo
method to determine where a value should be allocated.
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