i am new to java and was learning the concepts of hashmaps.
I am confused how the keys are sorted in hashmaps.
i understood that its based on string length.
but i am confused how data is sorted when the string length is same.
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class HashMapExample
{
public static void main(String args[])
{
Map<String,String> map = new HashMap<String,String>(20);//SPECIFYING THE TYPE FOR FINDING HASH CODES.
//Adding values to the HashMap
map.put("key value a", "test value 1");
map.put("key value b", "test value 2");
map.put("key value c", "test value 3");
System.out.println("Retrieving values from HashMap");
retrieveValuesFromListMethod(map);
System.out.println("**********************");
}
/*This method retrieves values from Map
*/
public static void retrieveValuesFromListMethod(Map map)
{
Set keys = map.keySet();
Iterator itr = keys.iterator();
String key;
String value;
while(itr.hasNext())
{
key = (String)itr.next();
value = (String)map.get(key);
System.out.println(key + " - "+ value);
}
}
}
this is my code.
output is
Retrieving values from HashMap
key value c- test value 3
key value b- test value 2
key value a- test value 1
**********************
but instead of a,b,c if i give aa,ab,ac the output is different
Retrieving values from HashMap
key value ab - test value 2
key value aa - test value 1
key value ac - test value 3
**********************
for 1,2,3
Retrieving values from HashMap
key value 1 - test value 1
key value 2 - test value 2
key value 3 - test value 3
**********************
how sorting is done in hashmap? Please help!!
Thanks in advance.
java.util.HashMap is unordered; you can't and shouldn't assume
anything beyond that.
This class makes no guarantees as to the order of the map; in particular, it does not guarantee that the order will remain constant
over time.
java.util.LinkedHashMap uses insertion-order.
This implementation differs from HashMap in that it maintains a doubly-linked list running through all of its entries. This linked
list defines the iteration ordering, which is normally the order in
which keys were inserted into the map (insertion-order).
java.util.TreeMap, a SortedMap, uses either natural or custom ordering
of the keys.
The map is sorted according to the natural ordering of its keys, or by a Comparator provided at map creation time, depending on which
constructor is used.
java beginner : How key gets sorted in hashmaps?
Taking from answer from here which is also the answer to your question
Use sorted TreeMap:
Map<String, Float> map = new TreeMap<String, Float>(yourMap);
It will automatically put entries sorted by keys. I think natural String ordering will be fine in your case.
Note that HashMap due to lookup optimizations does not preserve order.
If you want to preserve the order in which the data was inserted into the map you can use LinkedHashMap.
In your case , when you are using the following
//Adding values to the HashMap
map.put("key value a", "test value 1");
map.put("key value b", "test value 2");
map.put("key value c", "test value 3");
here is the snap of hashmap after the insertion of the keys
HashMap internally uses Array of Entry Map , hashcode generated by the keys are input to the hashing function that makes this key to be inserted in the array in the order you are looking into it .
You are using iterator to iterate the hashmap ,have a look at the snap of iterator for the above collection, since the iterator is looking at the collection in the following order , it just seems the keys are sorted but are actually not .
(Note : Iterator doesn't guarantee for the iteration in the order in which the elements are present in collection )
so its just a resemblance not the actual behavior of hashmap . This behavior for sorted key is given by TreeMap or any collection implementing interface SortedMap and the key when comparable .
I hope above information will be helpful to you
A Hashmap is not sorted.
If you have to keep the order, you have to use e.g. LinkedHashMap<K, V>
Try TreeMap,
Map<String, String> sampleMap = new TreeMap<String, String>(map);
use TreeMap the all keys are in sorted order
hashmap is not sorted, the output is different because the String's hashcode is not same.
Related
This question was asked to me in a job interview and I still don't know answer so ask here. Lets say hashCode() of key object returns a fixed integer so HashMap would look like a LinkedList.
How would a duplicate element be found and replaced by new value in map?
e.g. if following 1001 puts are performed in order listed below,
put(1000,1000), put(1,1), put( 2, 2), put ( 3,3 ) ....put(999,999), put(1000,1000 )
Would map be traversed all the way to end and then new one be inserted at head when last put(1000,1000) is performed?
OR
Map has some other way to locate and replace duplicate keys?
First case is correct.
In your case when hashCode() is returning same hash value for all the keys. In the java HashMap, Key and Value both are stored in the bucket as Map.Entry object. When perform the second or further put() operations into the map, it will traverse all the element to check whether Key is already present in the Map. If Key is not found then new Key and Value pair will be added into the linked list. If Key is found in the list then it update the Value for the pair.
Details explanation about java HashMap working: How HashMap works in Java
Take this sample code and run in the debug mode and observe how the new Key and Value pair are inserted into the Map.
In the class you will need to hashCode() (we want to control how the hash codes are generated for Node), toString() (just to output the Node value in SOUT) and equals() (defines the equality of the keys based on the value of Node member variable Integer, for updating the values.) methods for getting it working.
public class HashMapTest {
static class Node {
Integer n;
public Node(int n) {
this.n = n;
}
#Override
public int hashCode() {
return n%3;
}
#Override
public boolean equals(Object object) {
Node node = (Node)object;
return this.n.equals(node.n);
}
#Override
public String toString() {
return n.toString();
}
}
public static void main(String[] args) {
Map<Node, String> map = new HashMap<>();
for (int i = 0; i<6; i++) {
map.put(new Node(i), ""+i); // <-- Debug Point
}
map.put(new Node(0), "xxx");
} // <-- Debug Point
}
First 3 entries in the map: (hash code is n%3)
Three more values: (hash code is n%3)
Now don't confused about the ordering of the node, I have executed them on java 1.8 and HashMap uses TreeNode, an implementation of Red-Black tree as per the code documentation. This can be different in different versions of the java.
Now lets update the Value of Key 0:
When the hash code is the same, the hash map compares objects using the equals method.
For example, let's say you put a bunch of elements in the hash map:
put(1000,1000), put(1,1), put( 2, 2), put ( 3,3 ) ....put(999,999)
And then you do this:
put(1000,1000 )
1000 is already in the map, the hash code is the same, it is also the same in terms of the equals method, so the element will be replaced, no need to iterate further.
Now if you do:
put(1234, 1234)
1234 is not yet in the map. All the elements are in a linked list, due to the fixed hash code. The hash map will iterate over the elements, comparing them using equals. It will be false for all elements, the end of the list will be reached, and the entry will be appended.
JDK implementations changes over time !
In JDK8, if the hashCode() is a constant value, the implementation creates a tree not a linked list in order to protect against DDOS attack 1.
I'm trying to come up with an efficient way to return a key in my HashMap that has the lowest value in datastructure. Is there a quick and efficient way to do this besides looping through the entire HashMap?
For example, if I have a hashmap that looks like this:
1: 200
3: 400
5: 1
I want to return the key, 5.
No, you have to loop over all the keys in a HashMap to find the smallest. If this is an important operation, you're better off using a SortedMap, for instance TreeMap, which keeps its elements in sorted order, and then you can simply call firstKey() to find the lowest key.
As others have mentioned HashMap itself does not provide this.
So your options are to either compute it on-demand or pre-compute.
To compute it on-demand, you would iterate the HashMap.entrySet()
Depending on the size of the map, frequency of its change and frequency of requiring the key-with-lowest-value, pre-computing (caching) may be more efficient. Something as follows:
class HashMapWithLowestValueCached<K, V extends Comparable> extends HashMap<K, V> {
V lowestValue;
K lowestValueKey;
void put(K k, V v) {
if (v.compareTo(lowestValue) < 0) {
lowestValue = v;
lowestValueKey = k;
}
super.put(k, v);
}
K lowestValueKey () { return lowestValueKey; }
}
No, there is no way of doing this. You need to iterate over all the elements in the HashMap to find the one with the lowest value.
The reason why we have different kinds of storage is that they support different kinds of operations with different efficiency. HashMap is not designed to retrieve elements efficienctly based on their value. The kind of storage class you need for this will depend on what other operations you need to be able to do quickly. Assuming that you probably also want to be able to retrieve items quickly based on their key, the following might work:
Write a wrapper around your HashMap that keeps track of all the elements being added to it, and remembers which oneis the smallest. This is really only useful if retriving the smalls is the only way you need to access by value.
Store all your data twice - once in a HashMap and once in a data structure that sorts by value - for example, a SortedMap with key and value reversed.
If you find you don't need to retrieve by key, just reverse key and value.
No, there is no quick and efficient way of doing that - you need to loop through the entire hash map. The reason for it is that the keys and values in hash maps do not observe any particular order.
No, because otherwise there would exist a sorting algorithm in O(n log n) (probabilistic, though): add all elements to the hash map, than extract the lowest one by one.
//create hashmap
HashMap<Integer, String> yourHashmap = new HashMap<>();
//add your values here
yourHashmap.put(1,"200");
yourHashmap.put(3,"400");
yourHashmap.put(5,"1");
//then create empty arraylist
ArrayList<Integer> listDuplicates = new ArrayList<Integer>();
//filing the empty arraylist with all id's from duplicateHashmap
for (Map.Entry<Integer, String> entry : yourHashmap.entrySet()) {
listDuplicates.add(entry.getKey());
}
//Ordering the numbers
Collections.sort(listDuplicates);
for (Integer num : listDuplicates) {
int id = num; //entry
String number2 = duplicateHashmap.get(num);//value
System.out.println("lowest value = "+id+" : "+number2);
//breaking here because we've found the lowest value...
break;
}
Unlike HashMap, order matters in LinkedHashMap. And the order here is insertion order.
Let say I have a LinkedHashMap like the following (ordered from the top to bottom, left part is key, right part is value):
1:"One"
2:"Two"
3:"Three"
4:"Four"
Then I have a list of keys, which contains, let's say, (3,1).
What I want to do is to loop through the LinkedHashMap in order and pick out the entries whose key is in the list.
So the result I want to have is (1 is still before 3 because that's the order before filtering):
1:"One"
3:"Three"
Here is my code:
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public class SelectCertainEntriesFromLinkedHashMap {
public static void main(String args[]) {
Map<Integer,String> linkedHashMap = new LinkedHashMap<Integer,String>();
linkedHashMap.put(1, "One");
linkedHashMap.put(2, "Twe");
linkedHashMap.put(3, "Three");
linkedHashMap.put(4, "Four");
List<Integer> list = new ArrayList<Integer>();
list.add(3);
list.add(1);
Map<Integer,String> selectedlinkedHashMap = new LinkedHashMap<Integer,String>();
//will this iterator iterate the keys in the order of the map (1, 2, 3, 4)? Or just random order?
Iterator<Integer> itr = linkedHashMap.keySet().iterator();
while(itr.hasNext()) {
Integer key = itr.next();
if (list.contains(key)) {
selectedlinkedHashMap.put(key, linkedHashMap.get(key));
System.out.println(key + ":" + linkedHashMap.get(key));
}
}
}
}
The above code return the result I like. But I am not sure if it is guaranteed.
1:"One"
3:"Three"
The question is:
Iterator itr = linkedHashMap.keySet().iterator();
The above line will get a iterator from a set and set is not ordered. So will this cause the keys in random order? if yes, I can't keep the original order (not guaranteed) of my map after filtering....
Could anybody help me with this?
The iterator returned from keySet().iterator() should return an ordered Set. Documentation from the Map API:
The Map interface provides three collection views, which allow a map's contents to be
viewed as a set of keys, collection of values, or set of key-value mappings. The order of
a map is defined as the order in which the iterators on the map's collection views return
their elements. Some map implementations, like the TreeMap class, make specific guarantees
as to their order; others, like the HashMap class, do not.
So in the LinkedHashMap case I interpret this as saying the iterator will return an ordered Set. It's true the LinkedHashMap API is not explicit about this but you could just try it out and observe your output.
When you call keySet(), that creates a view of the keys based on the underlying data. Admittedly it's not very clearly documented, but as it is just a view, it would be incredibly weird for that view to be iterated in a different order.
You could check the implementation of course, but I'm sure it's fine.
have you tried it? I'm not sure it returns them in the same order as they were inserted, but in this particular case, you could create a TreeSet with the KeySet obtained and since they are integers its gonna be naturally order. 1 and then 3.
kinda like:
Set<Integer> set = new TreeSet<Integer>(linkedHashMap.keySet());
I require to get the list of keys where the values are equal for those keys from a HashMap.
For example , my hashmap contains the below elements.
Key Value
1 a,b
2 e,c
3 a,b
4 f
5 e,c
6 c
We need to evaluate as
1,3 contains value (a,b)
2,5 contains value (e,c)
4 contains value (f)
6 contains value (c)
Thx
You could invert your hash: build a new hash with the key type being the type of your current map's value, and the value type being a list of your current map's key type.
Iterate over your current map's keys, and push them to the right slot in your new map. You'll then have exactly the mapping you are asking for.
If the values in your current map aren't directly comparable right now, you'll need to find a representation that is. This depends completely on the nature of the data.
One simple approach is to sort the list and use it's toString representation as your new key. This only works if the toString representation of the underlying objects is sane for this purpose.
You can create other map where your keys a used as values and values as keys. If for example your source map is defined as Map<Integer, String> create map Map<String, List<Integer>>. The list of integers will contain keys (from your source map) that have certain values.
Building on Mat's answer, if you need to do this operation frequently, use one of the bidirectional map classes from Guava or Apache Commons Collections; e.g. HashBiMap<K,V> or DualHashBidiMap or DualTreeBidiMap. These data structures maintain a pair of maps that represent the forward and inverse mappings.
Alternatively, for a once off computation:
Extract the Map.entries() collection into an array.
Sort the array in order of the values.
Iterate the array, and extract the entry keys for which subsequent entry values are equal.
(This should be O(NlogN) in time and require O(N) extra space ... depending on the sort algorithm used.)
The most basic method will be to:
Get the first key of the HashMap and iterate over the map checking for keys with the same value.
If found, remove that key from the map and store the key in another collection (maybe a Vector).
Then after all other keys are checked, add the current key to that collection.
If no other keys are found, add the current key to that collection.
Then add the keys in that collection to another map with the relevant value. Clear the collection.
Proceed to the next key and do the same.
After doing this, you will end up with what you want.
EDIT: The Code:
HashMap comp = new HashMap(); // Calculations Done
Vector v = new Vector(); // Temporary List To Store Keys
// Get The List Of Keys
Vector<Integer> keys = new Vector<Integer>();
Iterator<Integer> it = hm.keySet().iterator();
while(it.hasNext()) keys.add(it.next());
// For Every Key In Map...
for(int i = 0; i < hm.size(); i++) {
int key = keys.get(i);
v.add(key); // Add the Current Key To Temporary List
// Check If Others Exist
for(int j = i+1; j < hm.size(); j++) {
int nkey = keys.get(j);
if(hm.get(key).equals(hm.get(nkey))) {
v.add(nkey);
}
}
// Store The Value Of Current Key And The Keys In Temporary List In The Comp HashMap
String val = hm.get(key);
String cKey = "";
for(int x = 0; x < v.size(); x++)
cKey += v.get(x) + ",";
// Remove The Comma From Last Key, Put The Keys As Value And Value As Key
cKey = cKey.substring(0, cKey.length()-1);
comp.put(cKey, val);
// Clear The Temporary List
v.clear();
}
There is a little problem in this code: Duplicates occur and also the last duplicate seems to be correct.
The output using your example give. (You need to do a little formatting).
{3=a,b, 6=c, 5=e,c, 2,5=e,c, 4=f, 1,3=a,b}
I am having some problem with java hashtable. Following is my hastable key and values
{corpus\2.txt=[cat sparrow], corpus\4.txt=[elephant sparrow], corpus\1.txt=[elephant cow], corpus\3.txt=[cow cat]}
So if i want to access first tuple i have to pass key "corpus\2.txt" to get its value. If i pass value i can get it's key. But I want to make a function I pass like 1 2 3 4 etc. and get both key and value. Any idea?
2nd question:
Is it possible to store an index with key and value too?? Or is it possible to get index ( 0,1,2,3 etc. ) from existing hashtable?
Thanks !
For starters, I would use a HashMap, rather than the (now obsolete) HashTable. If you do that, then you can use Map.Entry to return a key/value pair (as per your first question).
You can't easily store an index with your key. You might want to create a special Key object thus:
public class Key {
private String name;
private int index;
....
}
with a suitable equals()/hashCode() implementation (as pointed out below in the comments) and use that as the key in your HashMap. You've have to perform a lookup using this key and thus construct one from your current String-based key, but I don't think that's a big deal.
There is no method in the API to get a specific entry from a Java hash table. You can access the collection of all entries with the entrySet method, and iterating over that you will get all the key-value pairs as Map.Entry objects.
Hash tables are completely unordered. They are just mappings from keys to values and do not have any definite indices. There is a specific order that the entries will be processed if you iterate over the entrySet result, but this might also change when you modify the hash table.
Take a look at LinkedHashMap, a map implementation that preserves input ordering.
Rather use a Map<Integer, ValueObject> wherein ValueObject is just a custom javabean class with two properties e.g. filename and description.
Basic kickoff example:
public class ValueObject {
private String filename;
private String description;
public ValueObject() {
// Always keep default constructor alive.
}
public ValueObject(String filename, String description) {
this.filename = filename;
this.description = description;
}
// Add/generate public getters and setters for filename and description.
}
which you can use as follows:
Map<Integer, ValueObject> map = new HashMap<Integer, ValueObject>();
map.put(1, new ValueObject("corpus1.txt", "elephant cow"));
map.put(2, new ValueObject("corpus2.txt", "cat sparrow"));
map.put(3, new ValueObject("corpus3.txt", "cow cat"));
map.put(4, new ValueObject("corpus4.txt", "elephant sparrow"));
ValueObject vo = map.get(1); // Returns VO with corpus1.txt and elephant cow.
There's no way to access a Map by index. However, if what you really want to do is access the key-value pairs in the map one by one, you can just do:
for (Map.Entry<String, List<String>> nameAndWords: hashmap) {
String name = nameAndWords.getKey();
List<String> words = nameAndWords.getValue();
// do your stuff here
}
If you actually need indexing, you can add an external order to the map by keeping the keys in a list, which must be updated when you edit the map:
HashMap<String, List<String>> wordsByCorpus;
List<String> corpusNames;
public void addCorpus(String name, List<String> words) {
List<String> oldValue = wordsByCorpus.put(name, words);
if (oldValue == null) corpusNames.add(name);
}
public void removeCorpus(String name) {
wordsByCorpus.remove(name);
corpusNames.remove(name);
}
public Map.Entry<String, List<String>> getCorpus(int i) {
String name = corpusNames.get(i);
List<String> words = wordsByCorpus.get(name);
return wordsByCorpus.new SimpleImmutableEntry(name, words); // 1.6 only!
}
You either want to use a LinkedHashMap which allows you to access values added to the map using the index of the order they were added in.
Or you want to use 2 HashMaps. One to index by the string value and the second one to convert the integer value into the string value key of the first map. Then simple to get key and value from index:
String key = mapByIntToStringKey.get(index);
V value = mapByStringKey.get(key);
// now have both key and value, no linear searching so should be fast
Thus your maps would contain:
mapByStringKey={corpus\2.txt=[cat sparrow], corpus\4.txt=[elephant sparrow], corpus\1.txt=[elephant cow], corpus\3.txt=[cow cat]}
mapByIntToStringKey{2=corpus\2.txt, 4=corpus\4.txt, 1=corpus\1.txt}
although this is assuming that all your keys are not simply "corpus"+index+".txt".
If all keys are as above then if the indexes are not sparse then you could use a simple ArrayList (previously mentioned) and use get(index) which is fast (directly looks up in an array, can't get much faster than that), and then reconstruct the string key using the expression above.
If the indexes are sparse (i.e. some are missing, there are gaps) then just use the mapByIntToStringKey but replace with mapByIntToValue and reconstruct any string key you need using previous string expression.
The current high answer seems very odd to me, in that the suggestion is to key the map using the int index bit only of a compound key. Unless I'm reading it wrong, it means that you loose the ability to lookup values in the map using the string key alone or maybe just implies that you can always deduce the int index from the string key.