I want to search for a key in a hashmap and find the nearest one to that key!
HashMap map = new HashMap();
Using a NavigableMap like a TreeMap
long key =
NavigableMap<Long, Object> map = new TreeMap<Long , Object>();
Long before = map.floorKey(key);
Long after = map.ceilingKey(key);
if (before == null) return after;
if (after == null) return before;
return (key - before < after - key
|| after - key < 0)
&& key - before > 0 ? before : after;
Hashes (including HashMap) have no ordering (implement 'Comparable'), they just work with the implementations of equals() and hashCode().
In other words, it can not be done. You may try with an ordered list or set.
You cannot do it with HashMap
without iterating over all of its keys. I assume that this is not what you are after, so here is a way do it with a TreeMap
:
TreeMap<Long,Object> map = new TreeMap<Long,Object>();
Long key = 42;
Map.Entry<Long,Object> low = map.floorEntry(key);
Map.Entry<Long,Object> high = map.ceilingEntry(key);
Object res = null;
if (low != null && high != null) {
res = Math.abs(key-low.getKey()) < Math.abs(key-high.getKey())
? low.getValue()
: high.getValue();
} else if (low != null || high != null) {
res = low != null ? low.getValue() : high.getValue();
}
If you are inserting values into the hashMap in a sorted order you could use a LinkedHashMap so that the insertion order can be maintained.
Now we can perform a binary search over the keys instead of iterating over all keys (like in some of the other answers).
If iteration over all keys took n comparisons, binary search would take log(n)with base 2 comparisons.
The point to note here would be that this works only if the map is sorted.
A hash map is good as a general purpose map implementation that provides rapid storage and retrieval operations. However, it falls short because of its chaotic and unorderly arrangement of entries.
This causes it to perform poorly in scenarios where there is a lot of iteration as the entire capacity of the underlying array affects traversal other than just the number of entries.
We could say a linked hash map reduces the chaos in the ordering of a hash map without incurring the performance penalty of a tree map.
Iterate over all the keys to find the key with the lowest difference to your target key.
Here's some code that does that:
public static Long nearestKey(Map<Long, Object> map, Long target) {
double minDiff = Double.MAX_VALUE;
Long nearest = null;
for (long key : map.keySet()) {
double diff = Math.abs((double) target - (double) key);
if (diff < minDiff) {
nearest = key;
minDiff = diff;
}
}
return nearest;
}
All that casting to double
is to guard against a rollover when target is a large negative and the map key is a large positive
Not? That's not how the get function is supposed to work. I guess you might be able to use a TreeMap and use the getHeadMap/getTailMap and use some logic to find the closest match. But that would probably require to fiddle around a bit. After all what would the closest imply? ...