Fast look up of key by value without creating an inverse hashmap? - java

If I have a HashMap<KEY, VALUE> and I need fast look up of the key by the value is there any other approach besides creating a second HashMap<VALUE, KEY> that store the same data but using the value as the key?
Is there any approach/tick about this? If it makes a difference my interest is about String both as key and value
Note: I am on Java 7
Update:
I am not sure why the other question is a duplicate as I am asking a specific way on implementing this.
Unless the only/best way is a 2 way map I can't see why this is a duplicate

Short answer: no, there isn't.
You need two maps. If you want to use O(1) time for both, that means two hashmaps.
If you're worried about space, don't worry so much: you're just storing duplicate pointers, and not two strings.
I.e., you're just storing
HashMap<String* k, String* v> normal;
HashMap<String* k, String* v> inverse;
rather than entire strings. (Although pointers kind of don't exist in Java.)

Related

O(1) method of getting K using V with a java hashmap? [duplicate]

This question already has answers here:
Bidirectional Map
(9 answers)
Closed 4 years ago.
In Java 8 is there an O(1) method of getting the K by using V for a hashmap? Would I have to use two hashmaps(KV and VK) and if so would that defeat the purpose of having O(1)?
For context, I am trying to find the most efficient way of getting (String userName, Integer userIdentifier) using either value or key.
As a general note - there's a hidden assumption here that the values are also unique. Otherwise, you won't be able to retrieve a single key by a value, but a list of keys, although even if you take that into consideration it won't change the answer much. Additionally, with your usecase of userName and userId, this may be a moot point altogether.
As you alluded, a simple HashMap won't be enough - that would mean you'd need to iterate over the entries to find an entry with a specific key, which would be an O(n) operation.
Using two HashMaps (name to id and id to name) is a good approach. While this would mean you'd have to perform two operations instead of one each time you add/remove/modify a user, it won't affect the order of magnitude (since you're still performing a constant number of constant-time operations), and you'll retain the O(1) insertion time.
This is in fact a pretty common approach, and if you can introduce third-party libraries to your project, there are pretty solid implementations of this concept out there, like Apache Commons Collections' DualHashBidiMap.
Maps are meant for searching by key, so you won't get O(1) lookup by value, unless you use a second map.
What serves your use case is a BiMap avaliable from Google Guava
BiMap<String, Integer> nameidmap = HashBiMap.create();
Integer id = nameidmap.get("name");
String name = nameidmap.inverse().get(12345);
Internally Guava also maintains two hash tables, but it does the heavy lifting of keeping the two maps in sync. You can find full Javadoc for Bimap here.
If you want to use only single hashmap, you can do
map.put(key, value) and then map.put(value, key)
Assuming values are unique and also not equal to any key

A Collection that associates keys to values, and where both a key and a value can be obtained by index

By indexed I mean keys and values can be accessed via an index representing the order in which they were inserted into the collection.
I need a collection that behaves like a Map<K, V>, but also a List<K>(Read-Only) and a List<V>(also Read-Only). My naive implementation is to wrap a HashMap<K, V> and 2 ArrayList, but that leads to massive data redundancy and poor perfomance. Then I thought about LinkedHashMap<K, V>, which would work a lot better in this case, but the getByIndex operations would not perform well, because that would require navigating the internal Linked Nodes, which for small quantities of data is perfectly acceptable, but I'm not exactly sure how will the list be used by client code.
In short, is there something that suits my requirements better than the alternative?
EDIT: If I had something like pointer arithmetics and low level functions like memcpy and a runtime sizeof operator resolving the sizes of K and V, then maybe I could come up with a very efficient implementation. Are there any equivalents to any of that in Java?
I can suggest you few indirect ways.
You can create HashMap < Integer,HashMap< K,V > >. You can insert in this map keeping order as key and then can put the Key-value pair HashMap as value.
You can simply have a single ArrayList<K> and a HashMap<K,V>. For each entry to the map you can insert the key in the array list.
You can use (as you have said in the question itself) LinkedHashMap and can get the iterator or can use for each enhanced for loop for iteration. This way of iterating is efficient and for each step of iteration entire list is not iterated. But you can only iterate and not get the random indexed entry.
If third-party libraries are fair game, Guava's ImmutableMap does this nicely if you don't need mutation. Once it's created, you can use map.entrySet().asList(), map.keySet().asList(), and map.values().asList() to get, in O(1), random-access lists of the entries, keys, and values that support get(index) in O(1).

Java hashmap default size

Hi I have a situation where I have to store a single key value pair to my Hashmap . The map size is always constant. i.e., 1 . But default size of hash map is 16 bits . Here am almost wasting nearly 15 bits. Is there any way to limit the size of the hashmap.
Thanks in Advance for your valuable suggestions .
You can provide an initial capacity in the HashMap constructor:
Map<String> map = new HashMap<>(1);
It looks like that is genuinely obeyed in the implementation I'm looking at, but I can easily imagine some implementations having a "minimum viable capacity" such as 16. You'd have to be creating a large number of maps for this to really be an issue.
On the other hand, if you really only need a single-entry map and you're in a performance-sensitive situation, I would suggest you might not want to use HashMap at all. It wouldn't be hard to write a Map implementation which knew that it always had exactly one entry (which would presumably be provided on construction). If your code depends on having a HashMap rather than a Map, you should check whether you really want that top be the case.
If you only need a pair of immutable values, you can use Pair class.
Pair Class
You always can keep the structure with this class, just use getLeft() for getting the key, and getRight() to return the value of your object.

Creating Dictionary in java?

Everywhere on net, here is the way
Map<String, String> map = new HashMap<String, String>();
map.put("dog", "type of animal");
System.out.println(map.get("dog"));
My point is should it not be Treemap considering dictionary has to be sorted? Agreed lookup wont be optimized in case of Treemap but considering sorting its best data structure
UPDATE :- one more requirement is return the lexicographically nearest word if the word searched is not present . I am not sure how to achieve it?
If you need the map sorted by its keys, then use TreeMap, which "...provides guaranteed log(n) time cost for the containsKey, get, put and remove operations." If not, use the more general HashMap (which "...provides constant-time performance for the basic operations (get and put), assuming the hash function disperses the elements properly among the buckets..."), or one of the other Map implementations, depending on your need.
If you want to get value for given key and if the probability of having the exact match of key in hashmap is less then using hashmap wont give you benefit of direct lookup.
If using TreeMap you can get list of keys which is already ordered and can perform a binary search on the list. While searching compare key lexicographically. Continue binary search till the lexicographic distance between two keys is minimum or 0.
Dictionary is no longer a term used in the language. You'll get multiple answers.
I know that Objective-C uses a class called Dictionary that is as a Key / Value data structure. The fact that it's named Dictionary leads me to believe that is the ordering of the objects, I imagine the Key has to be a string or char
So, it depends on the entire question.
When someone says they want to create a Key/Value data structure that is ordered alphabetically, or a "Dictionary", the answer is:
TreeMap<String, Object> map = new TreeMap<>()
If someone is asking how to create a Key/Value object similar to a Dictionary in whatever language, they will likely get any of the java.util classes that implement the Map<K, V> interface, for example HashMap, TreeMap. A good answer would be a TreeMap.
In this case telling someone to use a HashMap is not debatable, because the answer is as vague as the question.

java concurrent map sorted by value

I'm looking for a way to have a concurrent map or similar key->value storage that can be sorted by value and not by key.
So far I was looking at ConcurrentSkipListMap but I couldn't find a way to sort it by value (using Comparator), since compare method receives only the keys as parameters.
The map has keys as String and values as Integer. What I'm looking is a way to retrieve the key with the smallest value(integer).
I was also thinking about using 2 maps, and create a separate map with Integer keys and String values and in this way I will have a sorted map by integer as I wanted, however there can be more than one integers with the same value, which could lead me into more problems.
Example
"user1"=>3
"user2"=>1
"user3"=>3
sorted list:
"user2"=>1
"user1"=>3
"user3"=>3
Is there a way to do this or are any 3rd party libraries that can do this?
Thanks
To sort by value where you can have multiple "value" to "key" mapping, you need a MultiMap. This needs to be synchronized as there is no concurrent version.
This doesn't meant the performance will be poor as that depends on how often you call this data structure. e.g. it could add up to 1 micro-second.
I recently had to do this and ended up using a ConcurrentSkipListMap where the keys contain a string and an integer. I ended up using the answer proposed below. The core insight is that you can structure your code to allow for a duplicate of a key with a different value before removing the previous one.
Atomic way to reorder keys in a ConcurrentSkipListMap / ConcurrentSkipListSet?
The problem was to keep a dynamic set of strings which were associated with integers that could change concurrently from different threads, described below. It sounds very similar to what you wanted to do.
Is there an embeddable Java alternative to Redis?
Here's the code for my implementation:
https://github.com/HarvardEconCS/TurkServer/blob/master/turkserver/src/main/java/edu/harvard/econcs/turkserver/util/UserItemMatcher.java
The principle of a ConcurrentMap is that it can be accessed concurrently - if you want it sorted at any time, performance will suffer significantly as that map would need to be fully synchronized (like a hashtable), resulting in poor throughput.
So I think your best bet is to return a sorted view of your map by putting all elements in an unmodifiable TreeMap for example (although sorting a TreeMap by values needs a bit of tweaking).

Categories

Resources