Questions about Java's library map classes? - java

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.

Related

Combining remove and put method in LinkedHashMap

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/

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).

Java get values from LinkedHashMap with part of the key

I have the following key-value system (HashMap) , where String would be a key like this "2014/12/06".
LinkedHashMap<String, Value>
So, I can retrieve an item knowing the key, but what I'm looking for is a method to retrieve a list of the value which key matches partialy, I mean, how could I retrieve all the values of 2014?.
I would like to avoid solutions like, test every item in the list, brute-force, or similar.
thanks.
Apart from doing the brute-force solution of iterating over all the keys, I can think of two options :
Use a TreeMap, in which the keys are sorted, so you can find the first key that is >= "2014/01/01" (using map.getCeilingEntry("2014/01/01")) and go over all the keys from there.
Use a hierarchy of Maps - i.e. Map<String,Map<String,Value>>. The key in the outer Map would be the year. The key in the inner map would be the full date.
Not possible with LinkedHashMap only. If you can copy the keys to an ordered list you can perform a binary search on that and then do a LinkedHashMap.get(...) with the full key(s).
If you're only ever going to want to retrieve items using the first part of the key, then you want a TreeMap rather than a LinkedHashMap. A LinkedHashMap is sorted according to insertion order, which is no use for this, but a TreeMap is sorted according to natural ordering, or to a Comparator that you supply. This means that you can find the first entry that starts with 2014 efficiently (in log time), and then iterate through until you get to the first one that doesn't match.
If you want to be able to match on any part of the key, then you need a totally different solution, way beyond a simple Map. You'd need to look into full text searching and indexing. You could try something like Lucene.
You could refine a hash function for your values so that values with similar year would hash around similar prefixed hashes. That wouldn't be efficient (probably poor distribution of hashes) nor to the spirit of HashMaps. Use other map implementations such as TreeMaps that keep an order of your choice.

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?

Retrieving/modifying highest & lowest values in k/v pair map?

So I have encountered the situation where I have a k/v map of destination to quantity, i.e. {San Francisco -> 10}, and I want to retrieve the k/v pair with the highest or lowest value, and then after retrieving it, I want to modify the value. TreeMap obviously has this functionality, but for the keys, not the values. Are there any packages or other ways to achieve this functionality? Thanks.
You can use BiMap from google guava.
Key/value maps are inherently unordered in most implementations (because they are implemented using hash tables). You'd need to iterate over all the values to determine the maximum. You should consider using a tuple with both the key and value, and then insert the tuple in a data structure that supports ordering.

Categories