Combining remove and put method in LinkedHashMap - java

With a LinkedHashMap, when I try to reinsert same key with different value, it replaces the value and maintains the order of key i.e if I do this
Map<String,String> map = new LinkedHashMap<>();
map.put("a", "a");
map.put("b", "b");
map.put("c", "c");
map.put("d", "d");
map.values().stream().forEach(System.out::print);
Output: abcd
Now if I add in the map a different value with same key,the order remains the same i.e
map.put("b", "j");
map.values().stream().forEach(System.out::print);
Output: ajcd
Is there any other way? One is to remove and reinsert key with new value, which prints acdj as output. In my case I want to do it for multiple keys based on some property of object used as value?
Solution using streams would be preferable.

This linked list defines the iteration ordering, which is normally the order in which keys were inserted into the map (insertion-order). Note that insertion order is not affected if a key is re-inserted into the map
LinkedHashMap javadoc.
it keep track of the keys insertion, and if we add the Map.put javadoc :
If the map previously contained a mapping for the key, the old value is replaced by the specified value.
Map javadoc
The Entry is not replace, only the value is modified so the key remains the same.
You need to remove and then insert the value to update the ordering of the keys.

A HashMap is not sorted by either keys or values. What you are looking for is a TreeMap.
For a HashMap, the only guarantee is, that the keys are hashed and put in an array, based on their hash.
The LinkedHashMap, according to the Javadoc, creates an internal LinkedList, and tracks the original insertion order of entries. In other words, if you use LinkedHashMap, you won't, necessariely receive a 'sorted' list at all.
You have two options to work around this: Either use a TreeMap (or derivate thereof), or sort every time, you want to output the values. TreeMaps have an internal sorting, based on their keys. If the keys are compared to each other the way you'd expect (by comparing the Strings) then you get a properly ascending sorting, based on the keys. However this does not solve your problem, that you want to sort the values.
To solve your original problem, use a bidirectional TreeMap. Apache Commons4 implements such a map (https://commons.apache.org/proper/commons-collections/javadocs/api-4.3/org/apache/commons/collections4/bidimap/AbstractDualBidiMap.html#values--)
It allows you to access both a key and a value set. But be aware that this map will not work for you, if your values are not unique. Like keys, all values in a bidirectional map need to be unique, because they need to serve as keys themselves.
From the Javadoc:
This map enforces the restriction that there is a 1:1 relation between keys and values, meaning that multiple keys cannot map to the same value. This is required so that "inverting" the map results in a map without duplicate keys. See the put(K, V) method description for more information.

Hashmap insertion is based on hashcode only. For example a key of "b" has a hashcode as 98.
for map.put("b", "b");
you inserting as a key "b" which has hascode 98.
so it will look like. 98 ---> holds value 'b'.
again if you try to put on same key "b" which has a hashcode 98 only.
so hashmap try to link on same hashcode only which is 98 ---> holds "j" as a value.
for know working of hashmap hashcode check out below link
https://www.geeksforgeeks.org/internal-working-of-hashmap-java/

Related

Questions about Java's library map classes?

The answers are (2) and (4) but not sure why. I don't have much foundation on these topics. Could someone please explain why these are the correct answers and why the others are incorrect.
Thank you
A HashMap is a data structure that consists of keys and values. Values are stored in the HashMap with an associated key. The values can then be retrieved by recalling from the HashMap with the same key you used when putting the value in.
1
TreeMaps and LinkedHashMaps are different versions of a Map. A HashMap uses hashing to store its keys, whereas a TreeMap uses a binary search tree to store its keys and a LinkedHashMap uses a LinkedList to store keys. If you iterate over a HashMap, the keys will be returned in hash-sorted order (unpredictable in most cases), because that's how they were stored. The TreeMap, however, has a tree of all the values, so when you iterate over the tree, you'll get all the keys in actual sorted order. A LinkedHashMap has the keys in an ordered list, so an iterator will return the keys in the same order in which you inserted them.
2, 3, and 5
In a HashMap, values are looked up using their keys. If you had duplicate keys, the HashMap couldn't know which value to return. Therefore, every key in a HashMap must be unique, but the values do not have to be.
4
In a normal HashMap, the key is hashed and then inserted in the appropriate spot. With a TreeMap and a LinkedHashMap, you have the additional overhead of inserting the key into the tree or linked list which will take up additional time and memory.

Unsorted SparseArray

I have a SparseArray Key value Pair. The Key will be my ID and I'm sorting the value with separately maintained sort order numbers. But when I put data into SparseArray the key is sorted and sort order are changed according to Key. But i need the values exactly as I put into sort array. How can I
I beleive the description of sparse array clearly mentions the difference:
It is intended to be more memory efficient than using a HashMap to map Integers to Objects, both because it avoids auto-boxing keys and its data structure doesn't rely on an extra entry object for each mapping.
For further reading: http://developer.android.com/reference/android/util/SparseArray.html
OR
https://mathematica.stackexchange.com/questions/2369/finding-all-elements-within-a-certain-range-in-a-sorted-list
SparseArrays iteration over the keys using keyAt(int) with ascending values of the index will return the keys in ascending order, or the values corresponding to the keys in ascending order in the case of valueAt(int).

Collision resolution in Java HashMap

Java HashMap uses put method to insert the K/V pair in HashMap.
Lets say I have used put method and now HashMap<Integer, Integer> has one entry with key as 10 and value as 17.
If I insert 10,20 in this HashMap it simply replaces the the previous entry with this entry due to collision because of same key 10.
If the key collides HashMap replaces the old K/V pair with the new K/V pair.
So my question is when does the HashMap use Chaining collision resolution technique?
Why it did not form a linkedlist with key as 10 and value as 17,20?
When you insert the pair (10, 17) and then (10, 20), there is technically no collision involved. You are just replacing the old value with the new value for a given key 10 (since in both cases, 10 is equal to 10 and also the hash code for 10 is always 10).
Collision happens when multiple keys hash to the same bucket. In that case, you need to make sure that you can distinguish between those keys. Chaining collision resolution is one of those techniques which is used for this.
As an example, let's suppose that two strings "abra ka dabra" and "wave my wand" yield hash codes 100 and 200 respectively. Assuming the total array size is 10, both of them end up in the same bucket (100 % 10 and 200 % 10). Chaining ensures that whenever you do map.get( "abra ka dabra" );, you end up with the correct value associated with the key. In the case of hash map in Java, this is done by using the equals method.
In a HashMap the key is an object, that contains hashCode() and equals(Object) methods.
When you insert a new entry into the Map, it checks whether the hashCode is already known. Then, it will iterate through all objects with this hashcode, and test their equality with .equals(). If an equal object is found, the new value replaces the old one. If not, it will create a new entry in the map.
Usually, talking about maps, you use collision when two objects have the same hashCode but they are different. They are internally stored in a list.
It could have formed a linked list, indeed. It's just that Map contract requires it to replace the entry:
V put(K key, V value)
Associates the specified value with the specified key in this map
(optional operation). If the map previously contained a mapping for
the key, the old value is replaced by the specified value. (A map m is
said to contain a mapping for a key k if and only if m.containsKey(k)
would return true.)
http://docs.oracle.com/javase/6/docs/api/java/util/Map.html
For a map to store lists of values, it'd need to be a Multimap. Here's Google's: http://google-collections.googlecode.com/svn/trunk/javadoc/com/google/common/collect/Multimap.html
A collection similar to a Map, but which may associate multiple values
with a single key. If you call put(K, V) twice, with the same key but
different values, the multimap contains mappings from the key to both
values.
Edit: Collision resolution
That's a bit different. A collision happens when two different keys happen to have the same hash code, or two keys with different hash codes happen to map into the same bucket in the underlying array.
Consider HashMap's source (bits and pieces removed):
public V put(K key, V value) {
int hash = hash(key.hashCode());
int i = indexFor(hash, table.length);
// i is the index where we want to insert the new element
addEntry(hash, key, value, i);
return null;
}
void addEntry(int hash, K key, V value, int bucketIndex) {
// take the entry that's already in that bucket
Entry<K,V> e = table[bucketIndex];
// and create a new one that points to the old one = linked list
table[bucketIndex] = new Entry<>(hash, key, value, e);
}
For those who are curious how the Entry class in HashMap comes to behave like a list, it turns out that HashMap defines its own static Entry class which implements Map.Entry. You can see for yourself by viewing the source code:
GrepCode for HashMap
First of all, you have got the concept of hashing a little wrong and it has been rectified by #Sanjay.
And yes, Java indeed implement a collision resolution technique. When two keys get hashed to a same value (as the internal array used is finite in size and at some point the hashcode() method will return same hash value for two different keys) at this time, a linked list is formed at the bucket location where all the informations are entered as an Map.Entry object that contains a key-value pair. Accessing an object via a key will at worst require O(n) if the entry in present in such a lists. Comparison between the key you passed with each key in such list will be done by the equals() method.
Although, from Java 8 , the linked lists are replaced with trees (O(log n))
Your case is not talking about collision resolution, it is simply replacement of older value with a new value for the same key because Java's HashMap can't contain duplicates (i.e., multiple values) for the same key.
In your example, the value 17 will be simply replaced with 20 for the same key 10 inside the HashMap.
If you are trying to put a different/new value for the same key, it is not the concept of collision resolution, rather it is simply replacing the old value with a new value for the same key. It is how HashMap has been designed and you can have a look at the below API (emphasis is mine) taken from here.
public V put(K key, V value)
Associates the specified value with the
specified key in this map. If the map previously contained a mapping
for the key, the old value is replaced.
On the other hand, collision resolution techniques comes into play only when multiple keys end up with the same hashcode (i.e., they fall in the same bucket location) where an entry is already stored. HashMap handles the collision resolution by using the concept of chaining i.e., it stores the values in a linked list (or a balanced tree since Java8, depends on the number of entries).
When multiple keys end up in same hash code which is present in same bucket.
When the same key has different values then the old value will be replaced with new value.
Liked list converted to balanced Binary tree from java 8 version on wards in worst case scenario.
Collision happen when 2 distinct keys generate the same hashcode() value.
When there are more collisions then there it will leads to worst performance of hashmap.
Objects which are are equal according to the equals method must return the same hashCode value.
When both objects return the same has code then they will be moved into the same bucket.
There is difference between collision and duplication.
Collision means hashcode and bucket is same, but in duplicate, it will be same hashcode,same bucket, but here equals method come in picture.
Collision detected and you can add element on existing key. but in case of duplication it will replace new value.
It isn't defined to do so. In order to achieve this functionality, you need to create a map that maps keys to lists of values:
Map<Foo, List<Bar>> myMap;
Or, you could use the Multimap from google collections / guava libraries
There is no collision in your example. You use the same key, so the old value gets replaced with the new one. Now, if you used two keys that map to the same hash code, then you'd have a collision. But even in that case, HashMap would replace your value! If you want the values to be chained in case of a collision, you have to do it yourself, e.g. by using a list as a value.

Why does toString function of a HashMap prints itself with a different order?

I have this very simple piece of code, and I was just trying to play a bit with different kind of objects inside a Map.
//There's a bit of spanish, sorry about that
//just think 'persona1' as an object with
//a string and an int
Map mapa = new HashMap();
mapa.put('c', 12850);
mapa.put(38.6, 386540);
mapa.put("Andrés", 238761);
mapa.put(14, "Valor de 14");
mapa.put("p1", persona1);
mapa.put("Andrea", 34500);
System.out.println(mapa.toString());
And then I expect from console something like:
{c=12850, 38.6=386540, Andrés=238761, 14=Valor de 14, p1={nombre: Andres Perea, edad: 10}, Andrea=34500}
But susprisingly for me I got same data in different order:
{38.6=386540, Andrés=238761, c=12850, p1={nombre: Andres Perea, edad: 10}, Andrea=34500, 14=Valor de 14}
It doesn't matter if I try other kind of objects, even just Strings or numeric types, it always does the same, it makes a different without-apparently-any-sense order.
Can someone give me a hint why this happens? Or may be something too obvious I'm missing?
I'm using Java 1.7 and Eclipse Juno.
As per Oracle's documentation
The HashMap class is roughly equivalent to Hashtable, except that it is unsynchronized and permits nulls. 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.
Refer to HashMap JavaDocs.
There are 3 class which implements map interface in java.
1. hashMap: Id does not guarantee any order.
2. Linked HashMap:It will store them in insertion order.
3. TreeMap: It will store in ascending order.(ASCII value)
So As per your requirement you can use Linked HashMap instead of HashMap.so instead of writing
Map mapa = new HashMap();
create object of Linked HashMap
Map mapa = new LinkedHashMap();
follow below link for more info.
http://docs.oracle.com/javase/tutorial/collections/interfaces/map.html
HashMap not guaranteed the order of element. If you want to keep order use LinkedHashMap.
See following case
Map<Integer,String> unOrderedMap=new HashMap<>();
unOrderedMap.put(1,"a");
unOrderedMap.put(3,"a");
unOrderedMap.put(2,"a");
System.out.println("HashMap output: "+unOrderedMap.toString());
Map<Integer,String> orderedMap=new LinkedHashMap<>();
orderedMap.put(1,"a");
orderedMap.put(3,"a");
orderedMap.put(2,"a");
System.out.println("LinkedHashMap output: "+orderedMap.toString());
Output:
HashMap output: {1=a, 2=a, 3=a}
LinkedHashMap output: {1=a, 3=a, 2=a}
Maps does not maintain the order the order in which elements were added, List will maintain the order of elements
"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."
This is how a hashmap works: (citing from another source)
It has a number of "buckets" which it uses to store key-value pairs in. Each bucket has a unique number - that's what identifies the bucket. When you put a key-value pair into the map, the hashmap will look at the hash code of the key, and store the pair in the bucket of which the identifier is the hash code of the key. For example: The hash code of the key is 235 -> the pair is stored in bucket number 235. (Note that one bucket can store more then one key-value pair).
When you lookup a value in the hashmap, by giving it a key, it will first look at the hash code of the key that you gave. The hashmap will then look into the corresponding bucket, and then it will compare the key that you gave with the keys of all pairs in the bucket, by comparing them with equals().
Now you can see how this is very efficient for looking up key-value pairs in a map: by the hash code of the key the hashmap immediately knows in which bucket to look, so that it only has to test against what's in that bucket.
Looking at the above mechanism, you can also see what requirements are necessary on the hashCode() and equals() methods of keys:
If two keys are the same (equals() returns true when you compare them), their hashCode() method must return the same number. If keys violate this, then keys that are equal might be stored in different buckets, and the hashmap would not be able to find key-value pairs (because it's going to look in the same bucket).
If two keys are different, then it doesn't matter if their hash codes are the same or not. They will be stored in the same bucket if their hash codes are the same, and in this case, the hashmap will use equals() to tell them apart.
Now, when you put all your "key-value" pairs in the hashmap, and print them, it prints them in some random order of the keys which got generated by hashing the value you supplied for keys.
If your requirement is still to maintain the ordering, you can use the LinkedHashMap in Java.
Hope this helps :-)
Edit: Original Post: How does a Java HashMap handle different objects with the same hash code?

How to get the number of occurrences of a key in HashMap?

I am have the Hashmap like this,
HashMap<String,String> epnSource = new HashMap<String, String>();
Now I have added the keys/values like this,
epnSource.put("10.3.2.227","EPN1");
epnSource.put("10.3.2.227","EPN2");
epnSource.put("10.3.2.166","EPN3");
epnSource.put("10.3.2.166","EPN4");
epnSource.put("10.3.2.161","EPN5");
I am trying to do every time before adding a value, I want to check number of occurrences of a key present in the HashMap. Suppose if key 10.3.2.227 has more than two occurrences I shouldn't added it and go for new one. Any suggestions will be helpful.
Suppose if value 10.3.2.227 has more than two occurrences ...
It won't. The way that you have implemented it, the "10.3.2.227" is a key of the Map, and a given key cannot appear more than once in a Map.
If you want a given key (e.g. "10.3.2.227") to map to multiple values (e.g. "EPN1" and "EPN1"), you need to use either a Map<String,Set<String>> or a MultiMap class from the Apache or Google/Guava collections libraries.
If the map previously contained a mapping for the key, the old value is replaced.
It is not possible duplicate key in HashMap.

Categories