Reputation: 243
I am looking for an appropriate data structure for my problem. I would like to be able to select node objects as efficiently as possible using two keys. Insertion and deletion also needs to be efficient. Basically every node object has a pair of two keys. The pairs are unique but the individual keys are not. I need to be able to select a group of nodes that have a particular value for one of the two keys.
Example:
Node1 has keys a1 and b1
Node2 has keys a1 and b2
Node3 has keys a2 and b2
I would like to for example be able to select the node with the key a1,b1 but also all nodes that have b2 as key2.
I could of course make two HashMaps (one for each key) but this is kind of an ugly solution because when I add or remove something I would have to do it in both maps. Since there will be a lot of adding and removing going on I would prefer to do this in one go. Does anyone have any ideas about how to do this?
Obviously having a single key that merges the two keys together does not solve the problem because I also need to be able to search for a single key without having to search through the whole map. That wouldn't be very efficient. The problem is an efficiency problem. I could just search every entry in the map for a particular key but instead I would like to use a hash so that I can select multiple node objects using either one of the two keys instantly.
I am not looking for something like the MultiKeyMap because in this data-structure the first key always stays the same, you can only add keys instead of replacing the first key with a different key. I want to be able to switch between the first and the second key.
I do and do not want to store multiple objects with the same key. If you look at the example you can see that the two keys together are always unique. This can be seen as a single key therefore I would not store multiple objects under the same key. But if you look at the individual keys, these are not unique therefore I do want to store multiple objects referenced by the individual keys.
Upvotes: 8
Views: 14460
Reputation: 1
I think we can do it in this way: For each key, we can compute the corresponding hashcode.
key1 -> hashcode1
key2 -> hashcode2
Then we have a 2-d array, with N columns and N rows.
key1 -> rowIndex: hashcode1 MOD N
key2 -> columnIndex: hashcode2 MOD N
Then we store the item in array[rowIndex][columnIndex]
.
In this implementation, you can get all the entries with a target key1, and any key2. You can also get all the entries with a target key2, and any key1.
This array may expand when there are a lot of collisions, just like what you do with the ordinary hashmap.
Upvotes: 0
Reputation: 1579
You have to create a key class (equality is treated as Point):
public class Key {
int field1;
int field2;
public boolean equals(Object o) {
if (o == null || !(o instanceof Key)) return false;
Key other = (Key) o;
return field1 == other.field1 && field2 == other.field2;
}
public int hashCode() {
return field1*field2; // doesn't matter if some keys have same hash code
}
}
For selecting keys with one specific value in the first field:
public List<Key> getKeysWithField1EqualsTo(int value) {
List<Key> result = new ArrayList<>();
for (Key k: map.keySet()) {
if (k.field1 == value) result.add(k);
}
return result;
}
Upvotes: 5
Reputation: 10285
HashMaps can have any object as Key so why not create a class with 2 fields and consider this class as your key. you can also Override the Equals method to tell it how the keys are equals
Upvotes: 1
Reputation: 13994
Since a HashMap can only sort on one hash for every object, you will never be able to select the distinct lists 'out of the box'. What I would suggest is using a Tuple with two keys, and then iterate over the HashMap and select only those elements that have tuple.key1=X.
Upvotes: 1
Reputation: 726809
Since this is rather specific to your problem at hand, you will very likely need to develop your own collection. I would wrap two MultiMap
s from Apache Commons into my own collection class that deals with updates of both multi-maps at the same time, and use my class to perform inserts and queries.
Upvotes: 2
Reputation: 8582
If you can use a library, take a look at the Table interface of Guava. It associates a row and a column with a value. The row and columns may be your first and second keys. Also you can have searches by row or by column.
One of the implementations of this interface is hash based.
Upvotes: 6
Reputation: 2142
Write a simple class that is able to contain two values (the keys) and override equals(..) and hashCode() for equality checks used by the map. Use this simple class as the key for the map.
Here you can find a hashmap compatible pair class (2nd answer):
What is the equivalent of the C++ Pair<L,R> in Java?
Upvotes: 1