Java HashMap and underlying values() collection - java

I was wondering if the Collection view of the values contained in a HashMap is kept ordered when the HashMap changes.
For example if I have a HashMap whose values() method returns L={a, b, c}
What happened to L if I add a new element "d" to the map?
Is it added at the end, i.e. if I iterate through the elements, it's the order kept?
In particular, if the addition of the new element "d" causes a rehash, will the order be kept in L?
Many thanks!

I was wondering if the Collection view of the values contained in a HashMap is kept ordered when the HashMap changes.
No, there is no such guarantee.
If this was the case, then the following program would output and ordered sequence from 1-100
HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
for (int i = 0; i < 100; i++)
map.put(i, i);
System.out.println(map.values());
(and it doesn't).
There is a class that does precisely what you're asking for, and that is LinkedHashMap:
Hash table and linked list implementation of the Map interface, with predictable iteration 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).

If it doesn't say it in the JavaDoc then there are no guarantees about it. Different versions of Java could do different things. Don't depend on undocumented behaviour.
You might want to look at LinkedHashMap.

HashMap in Java aren't ordered, so I think it will be safe to say that values() won't return an ordered Collection.
LinkedHashMap is an ordered version of HashMap (insertion order), but I don't know it values() will return an ordered Collection. I think the best is to try.

Generally they is no guarantee of order when you are using HashMap. It might be in the order in which you add elements for a few elements but it would get reshuffled when there is a possibility of collision and it has to go with a collision resolution strategy.

Related

Iteration Order of HashMap key same or not

I want to know that HashMap is give same sequence of key when iterated each time after adding records.
I am using following code
HashMap<String,String> mapObj=new HashMap<String,String>();
mapObj.put("a", "aValue");
mapObj.put("b", "bValue");
mapObj.put("c", "cValue");
for(String key:mapObj.keySet()){
System.out.println(key+" :: "+mapObj.get(key));
}
for(String key:mapObj.keySet()){
System.out.println(key+" :: "+mapObj.get(key));
}
output of following program is
b :: bValue
c :: cValue
a :: aValue
b :: bValue
c :: cValue
a :: aValue
If you don't make any changes to the HashMap between the two iterations, you'll likely see the same iteration order (even though it's not guaranteed), since this is a deterministic data structure. However, adding or removing entries between the two iterations will probably change the iteration order.
If you want to rely on the iteration order, use LinkedHashMap, in which (by default) the keys are iterated in the order they were first added to the Map.
If you want to iterate over the keys in some specific order, you can use TreeMap instead (where the keys are ordered according to their natural ordering or the supplied Comparator).
Hash map accept the object to be stored as an argument and
generate a number that is unique to it.
HashMap uses hashing to store the entries in hashmap, so there is no gurantee those will appear in specific order. If you want your entries from your HashMap ordered, then you will have to sort it or you can use Treemap
HashMap doesn't maintain the order. If you want your elements to be retrieved in order then better to use LinkedHashMap.
Generally it would be little surprising if the iteration order changed for multiple subsequent invocations (assuming the map itself did not change in between). BUT you should not rely on it as API does not make any guarantee for that.
As per doc:
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.
You can use LinkedHashMap as its entrySetmaintain insertion ordering, as per Java Doc:
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).
TreeMap maintain the natural ordering of keys.
A Red-Black tree based NavigableMap implementation. 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.

How to get key position from a HashMap in Java

How can I get the key position in the map? How can I see on which position is "Audi" and "BMW"?
Map<String, Integer> map = new HashMap<String, Integer>();
map.put("Audi", 3);
map.put("BMW", 5);
As other answers state you need to use a structure like java.util.LinkedHashMap. LinkedHashMap maintains its keys internally using a LinkedEntrySet, this does not formally provide order, but iterates in the insertion order used.
If you pass the Map.keySet() into a List implementation you can make use of the List.indexOf(Object) method without having to write any of the extra code in the other answer.
Map<String, Integer> map = new LinkedHashMap<String, Integer>();
map.put("Audi", 3);
map.put("BMW", 5);
map.put("Vauxhall", 7);
List<String> indexes = new ArrayList<String>(map.keySet()); // <== Set to List
// BOOM !
System.out.println(indexes.indexOf("Audi")); // ==> 0
System.out.println(indexes.indexOf("BMW")); // ==> 1
System.out.println(indexes.indexOf("Vauxhall")); // ==> 2
You can't. The keys on a Map and a HashMap are not ordered. You'll need to use a structure that preserves order, such as a LinkedHashMap.
Note that LinkedHashMap does not provide a method that gets keys by position, so this is only appropriate if you are going to be using an iterator.
The alternative is to create a second Map that maps from your key to the Integer position, and add to it as you go along:
Map<String, Integer> indexMap = new HashMap<String, Integer>();
indexMap.put("Audi", 0);
indexMap.put("BMW", 1);
For a more elegant solution, you might need to give more information about what you're doing.
You can't. From the HashMap JavaDocs:
Hash table based implementation of the Map interface. This implementation provides all of the optional map operations, and permits null values and the null key. (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.
So, the order may vary between iterations. If you need to preserve the order you can take a look at LinkedHashMap
From the LinkedHashMap JavaDocs:
Hash table and linked list implementation of the Map interface, with predictable iteration 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).
So, to find the key position you basically need to iterate the keys and count the position of the key you are searching for.
On a side note, IMO this may not be the best use of the Map datatype. I believe that if you really need the position you should use some type of List (e.g. ArrayList) that actually preserves the order and you can use the get method to retrieve elements for a certain index.

Retrieve N most relevant objects in Java TreeMap

According to this question I have ordered a Java Map, as follows:
ValueComparator bvc = new ValueComparator(originalMap);
Map<String,Integer> sortedMap = new TreeMap<String,Integer>(bvc);
sortedMap.putAll(originalMap);
Now, I would like to extract the K most relevant values from the map, in top-K fashion. Is there a highly efficient way of doing it without iterating through the map?
P.S., some similar questions (e.g., this) ask for a solution to the top-1 retrieval problem.
No, not if you use a Map. You'd have to iterate over it.
Have you considered using a PriorityQueue? It's Java's implementation of a heap. It has efficient operations for insertion of arbitrary elements and for removal of the "minimum". You might think about doing this here. Instead of a Map, you could put them into a PriorityQueue ordered by relevance, with the most relevant as the root. Then, to extract the K most relevant, you'd just pop K elements from the PriorityQueue.
If you need the map-like property (mapping from String to Integer), then you could write a class that internally keeps everything in both a PriorityQueue and a HashMap. When you insert, you insert into both; when you remove the minimal element, you pop from the PriorityQueue, and that then tells you which element you also need to remove from your HashMap. This will still give you log-time inserts and min-removals.

Occurred order in the iteration at run-time in a map

In the piece of code similar to
//something before
Iteration<String> iterator = hashMap.keySet().iterator();// HashMap<String, Document>
while(iterator.hasNext()){
System.out.println(iterator.next());
}
//something after
I know that the order of print can be different by the order of insertion of entry key, value; all right.
But if I call this piece in another moment, with re-create the variable hashMap and putting them the equal elements, can the second-moment time print be different from the first-time print?
My question was born by a problem with a web-app: I have a list of String in a JSP, but, after some years, the customer call because the order of the String was different in the morning, but it shows the usual order at the afternoon.
The problem is happened in only one day: the web-app uses the explained piece of code for take a Map and populate an ArrayList.
This ArrayList does'nt any explicit changement of order (no Comparator or similar classes).
I think (hope) that the cause of different order of print derives by a different sequence of iteration in the same HashMap at run-time and I looking for a validation by other people.
In the web, I read that the iteration order by a HashMap changes if the HashMap receives a modification: but what happens if the HashMap remains the same?
Hash map document says HashMap makes no guarantees as to the order of the map; in particular, it does not guarantee that the order will remain constant over time.
that explains though the hashmap is same it can not guaranatee on order. for Ordered map you can use TreeMap or LinkedHashMap
TreeMap API says 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.
HashMap API documentation states 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.
For a Map that keeps its keys in original insertion order, use LinkedHashMap.
For a Map that keeps its keys in sorted order (either natural order or by you passing a Comparator), use either TreeMap or ConcurrentSkipListMap. If multi-threaded, use the second.
For a Map where the key an enum, use EnumMap if you want the entries ordered by the definition order of the enum's objects.
The other six Map implementations bundled with Java 11 do not promise any order to their entries.
See this graphic table of mine as an overview.
Use a LinkedHashMap instead, to preserve insertion order. From the javadoc: "Hash table and linked list implementation of the Map interface, with predictable iteration order."
If you just want a Map with predictable ordering, then you can also use TreeMap. However, a LinkedHashMap is faster, as seen here: "TreeMap has O(log n) performance for containsKey, get, put, and remove, according to the Javadocs, while LinkedHashMap is O(1) for each."
As Octopus mentioned, HashMap "makes no guarantees as to the order of the map," and you shouldn't use it if order must remain consistent.

LinkedHashMap LIFO or FIFO?

Is LinkedHashMap LIFO or FIFO in nature?
If my map is of the form:
map.put(1,"one");
map.put(2,"two");
what would be the order if I was to iterate on the map using keyset??
EDIT: I think I did actually confuse two different concepts. Let me rephrase the question. What would be the order in which I encounter the quantities using entryset?Thanks for pointing that out btw. I do not intend to remove any entry.
In a linked hash map the elements in the backing doubly-linked list are added at the end (clearly: for preserving iteration order), but can be removed from any part in the list as the elements get removed from the map, it's incorrect to label the backing list (and by extension: the map) as LIFO or FIFO, it's neither - there's no concept of removal order in a map, and consequently no removal order can be assumed for the backing list in a linked hash map.
What a linked hash map does guarantee is that iterating over its contents (be it: the keys or the entries) will occur in the same order in which the elements were inserted in the map; from the documentation:
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).
EDIT :
Regarding the last edit to the question, a LinkedHashMap guarantees that the iteration order of the keySet() will be the same order in which the elements were inserted: 1, 2 for the example in the question. This has nothing to do with FIFO/LIFO, those concepts deal with the order in which elements are removed from a data structure, and they're not related with the iteration order after inserting elements.
LinkedHashMap to quote from the javadocs is "Hash table and linked list implementation of the Map interface, with predictable iteration order" . So the keySet will return keys based on the order of insertion, esssentially a FIFO.
When access order is not utilized (standard case) you can consider LHM as a linked list w/ very fast access O(1) by key.
In that aspect it is FIFO when access order is unused (look at the c-tors). When access order is used the insertion order doesn't matter if there are any get() operations as they reorder the Entries. Look at protected boolean removeEldestEntry(Map.Entry<K,V> eldest) eldest=FIFO.
Essentially the LHM is a good doubly linked list of Map.Entry<Key, Value> with a hash index over the keys.
I myself never use the vanilla HashMap as in its current impl. it has very little benefit over LHM - lower memory footprint but horrid iteration. Java8 (or 9) perhaps may finally fix HashMap, hopefully Doug Lea will push his impl.
According to Java docs, if you were to iterate over the map, the keyset would be in insertion-order. So the first key you get is the first key entered, over the existing keys. Note, reinserting a key-value pair does not change the original key position.

Categories