Storing multiple values with same key in HashMap - java

I had an interview today and my interviewer asked me that how can I store multiple values having the same key in HashMap?
She gave me this example-->If I am given a list of String and I am suppose to store the length of String as key and the String itself as value.
I gave her the following solution in how I will be using HashMap:
Map<Integer, ArrayList<String>> map = new HashMap<Integer, ArrayList<String>>();
Integer being the length of the String and the ArrayList will store the Strings of that particular length.
The interviewer said that this is one way of using the HashMap but there is another way in which I won't be requiring ArrayList or any other data structure. During interview, I couldn't come up with any solution and now after enough googling, I still have nothing. Can anyone tell me how can I achieve the solution to this question?
Thanks!

One way without using ANY DATA STRUCTURE is concatenating all strings in values.
For e.g.
map.put(2,"rr*tt*yy");
map.put(3,"nnn*ggg*sss");
map.put(4,"ffff*dddd*jjjj");

May be the interviewer was looking to check if you know the 3rd party APIs or not.
There are multiple APIs available to do this.
Some of them can be found at
http://java.dzone.com/articles/hashmap-%E2%80%93-single-key-and

One option is every time you want to insert a record into the map, get the length of the String, salt then encrypt the size of the String to use as the key. BAM: you have a (fairly) unique retrievable key for each String without having to much around with String concatenation.
Just make sure you use a reversible encryption algorithm.
Another option would be to generate out a UUID and concatenate the size of the string to that.
UUID uuid = UUID.randomUUID()
String key = stringSize + "," + uuid;
This will also result in a unique value that you can retrieve later using String.split();

Related

HashMap - Fastest access using a key with several fields

I have an object that is identified by 3 fields. One them is a String that represents 6 hex bytes, the other two are integers of not more than 1 bytes each. This all summed up is 8 bytes of data, which fits in a 64 bit integer.
I need to map these objects for fast access, and I can think of two approaches:
Use the 3 fields to generate a 64 bit key used to map the objects. This however would mean parsing the String to Hex for every access (and there will a lot of accesses, which need to be fast).
Use 3 HashMap levels, each nested inside the next, to represent the 3 identifying fields.
My question is which of these approaches should be the fastest.
Why not use a MultiKeyMap?
This might be not related to your question.
I have a suggestion for you.
Create an object with the 3 attributes that will form the key. Use the object has the key because it will be unique.
Map<ObjectKey,Object> map = new HashMap<>();
This makes sense for your use case? If you can add a bit more explanation maybe I can go further in suggest you possible solutions.
EDIT: You can override the equals and do something using this kind of logic:
#Override
public boolean equals(Object obj) {
if (!(obj instanceof Key))
return false;
ObjectKey objectKey= (Key) obj;
return this.key1.equals(objectKey.key1) && this.key2.equals(objectKey.key2) &&
...
this.keyN.equals(objectKey.keyN)
}
I would take the following steps:
Write it in the most readable way first, and profile it.
Refactor it to an implementation you think might be faster, then profile it again.
Compare.
Repeat.
Your key fits into a 64-bit value. Assuming you will build the HashMap in one go and then read from it multiple times (using it as a lookup table), my hunch is that using a Long type as the key of your HashMap will be about as fast as you can get.
You are concerned about having to parse the string as a hex number every time you look up a key in the map. What's the alternative? If you use a key containing the three separate fields, you will still have to parse the string to calculate its hash code (or, rather, the Java API implementation will calculate its hash code by parsing the string contents). The HashMap will not only call String.hashCode() but also String.equals(), so your string will be iterated twice. By contrast, calculating a Long and comparing it to the precalculated keys in the HashMap will consist of iterating the string only once.
If you use three levels of HashMap, as per your second suggestion, you will still have to calculate the hash code of your string, as well as having to look up the values of all three fields anyway, so the multi-level map doesn't give you any performance advantage.
You should also experiment with the HashMap constructor arguments to get the most efficiency. These will determine how efficiently your data will get spread into separate buckets.

Get Value of HashMap using part of the key

I have an HashMap(String,Object). The key is combination of more than 1 unique ID. I have an input, a string which is part of the key(1 unique ID). I need to take the value in HashMap using that part of the key i have without iterating thousands of values in HashMap.
Can we achieve it using any Regex statement in HashMap.get()?
My Key is xxx.yyy.zzz where combination of xxx.zzz is unique throughout the Map. I have xxx and zzz as input. Also i have set of possible values of yyy(5-6 possibilities which may increase as well)for a given zzz.
I have two options to solve this now.
Map.Entry to check whether key starts and ends with xxx and zzz respectively
Trial and Error Method
i. Form key xxx.yyy.zzz with all possible yyys and check for whether the key is present or not using .contains()
ii. But this way, if i do .contains() 5-6 times for each call, won't it loop through 5-6 times at the worst case?
iii. Also i am creating more strings in stringpool.
Which one should i prefer?
The only way to retrieve a value from a HashMap without iterating over the entries/keys (which you don't want) is by searching for the full key.
If you require efficient search via a partial key, you should consider having a HashMap whose key is that partial key.
No, it's not possible to use partial keys with a HashMap.
With TreeMap this can be achieved with a partial prefix of the wanted key, as it allows you to use tailMap(String key) to return a part of the map that would follow a specific key (i.e. your keypart). You'd still need to process the entries to see which ones would match the partial key.
If your keys are like xxx.yyy.zzz and you want to use xxx.* type access then you could consider my MapFilter class.
It allows you to take a Map and filter it on a certain key prefix. This will do the searching for specific prefixes and retain the results of that search for later.
Can we achieve it using any Regex statement in HashMap.get()?
No.You can't. You need to pass the exact key to get the associated value.
Alternatively, you should itertate ober keys and get the values matched to it. They you can have regex to match your input string against key.
You cannot do this using a HashMap. However, you can use a TreeMap which will internally store the keys according to their natural order. You can write a custom search method which will find the matching key, if it exists, in the set using the regex. If written correctly, this will take O(lgN) time, which is substantially better than linear. The problem reduces to searching for a String in an ordered list of Strings.
As #Thilo pointed out, this solution assumes that you are trying to match a fragment of a key which starts at the beginning, and not anywhere else.
HashMap works on hashing algorithm that maintains hash buckets of hash code of keys and based on that hash code hash map retrieves corresponding value. For the you need to override equals() and hashcode() method for custom objects.
So
If you will try to get the value of a key, then key's hash code value get generated and further fetch operation happen based on that hash code.
If you would not give a exact match of key how HashMap will find out that bucket with a wrong hashcode ?

Mapping int to int (in Java)

In Java.
How can I map a set of numbers(integers for example) to another set of numbers?
All the numbers are positive and all the numbers are unique in their own set.
The first set of numbers can have any value, the second set of numbers represent indexes of an array, and so the goal is to be able to access the numbers in the second set through the numbers in the first set. This is a one to one association.
Speed is crucial as the method will have to be called many times each second.
Edit: I tried it with SE hashmap implementation, but found it to be slow for my purposes.
There's an article, devoted to this problem (with a solution): Implementing a world fastest Java int-to-int hash map
Code can be found in related GitHub repository. (Best results are in class IntIntMap4a.java )
Citation from the article:
Summary
If you want to optimize your hash map for speed, you have to do as much as you can of the following list:
Use underlying array(s) with capacity equal to a power of 2 - it will allow you to use cheap & instead of expensive % for array index
Do not store the state in the separate array - use dedicated fields for free/removed keys and values.
Interleave keys and values in the one array - it will allow you to load a value into memory for free.
Implement a strategy to get rid of 'removed' cells - you can sacrifice some of remove performance in favor of more frequent get/put.
Scramble the keys while calculating the initial cell index - this is required to deal with the case of consecutive keys.
Yes, I know how to use citation formatting. But it looks awful and doesn't handle bullet lists well.
The structure you are looking for is called an associative array. In computer science, an associative array, map, symbol table, or dictionary is an abstract data type composed of a collection of (key, value) pairs, such that each possible key appears just once in the collection.
In java in particular as already mentioned this is easily done with a HashMap.
HashMap<Integer, Integer> cache = new HashMap<Integer, Integer>();
You can insert elements with the method put
cache.put(21, 42);
and you can retrieve a value with get
Integer key = 21
Integer value = cache.get(key);
System.out.println("Key: " + key +" value: "+ value);
Key: 21 value: 42
If you want to iterate through data you need to define an iterator:
Iterator<Integer> Iterator = cache.keySet().iterator();
while(Iterator.hasNext()){
Integer key = Iterator.next();
System.out.println("key: " + key + " value: " + cache.get(key));
}
Sounds like HashMap<Integer,Integer> is what you're looking for.
If you are willing to use an external library, you can use apache's IntToIntMap, which is a part of Apache Lucene.
It implements a pretty efficient int to int map that uses primitives for tasks that should not suffer the boxing overhead.
If you have a limit for the size of the first list, you can just use a large array. Suppose you know there first list only has numbers 0-99, you can use int[100]. Use the first number as an array index.
Your requirements can be satisfied by the Map interface. As an example, see HashMap<K,V>.
See Map and HashMap

Store data as key value in array Java

In Javascript we can store values in array like
var arr=[];
arr["name"]="test";
arr["value"]="result";
console.log(arr["name"]);
above mentioned array is storing values like key value pair,my question is this we can achieve in java without using hashmap ? so that we can get value by key in java
I mean you could achieve it that way, but it is much less efficient. Searching an array for a specific value will be of O(n) complexity while hashmaps only take O(1) in the best case scenario (with no chaining).
It's not possible. Arrays are Integer Index based in Java.
HashMap is specifically designed for that purpose.

Which collection is suitable for tel number + name pair in Java?

I am trying to add to a collection the following pairs
698xxxxxxx - personA
698xxxxxxx - personB
699xxxxxxx - personA
699xxxxxxx - personB
I go through alot of files and try to add to a collection the pairs i find there. I want to be able to have a table that will show each number and what people it was correlated with without having dublicate PAIRS. for example
1-personA ok
1-personB ok
2-personA ok
3-personB ok
3-personB NOT OK as its already there
I tried using a Multimap but i m not sure if its the right choice. Whatever the solution is please show me how to iterrate through its values as well so i can use the pairs. Sorry for the demanding post but i m new with Java and i find a lil hard to understand the APIs.
Thanks in advance
There are three obvious alternative, depending on what you require.
If there can only be one person for each phone number, then a simple Map<PhoneNo, Name>.
If there a given phone number can be associated with multiple people, then either a Map<Phone,Set<Name>> or a multi-map class.
If you also want to find out the phone number or numbers for each person, you need two maps or two multi-maps ... or a bidirectional map.
There is a secondary choice you need to make: hash-table versus tree-based organizations. A hash table will give you O(1) lookup/insert/remove (assuming that the hash function is good). A tree-based implementation gives O(logN) operations ... but it also allows you to iterate over the entries (or values) in key order.
While the standard Java class libraries don't provide multi-maps or bidirectional maps, they can easily be implemented by combining the simple collection classes.
You can choose Map Interface in Java, which accepts key and value pairs.
You can have this as a reference: http://www.tutorialspoint.com/java/java_map_interface.htm
You may need a hashmap with the key as the name of the person and value as a HashSet of numbers. Hashset does not allow duplicates, so duplicate numbers will not be stored in that. Here is the code:
HashMap<String,HashSet> Records;
In Java there is a couple of options. If you don't know about the cardinality of persons or numbers, then go for:
public class Pair {
String person;
String number;
}
Then use a Set to be save from doublettes like
Set<Pair> pairs = new HashSet<>();
....
pairs.add( new Pair( "689xxxx", "personA" );
for ( Pair pair : pairs ) {
System.out.println( pair.number + " - " + pair.person );
}
Hajo

Categories