Same iteration order on Map.keySet and Map.values? - java

For a map like:
Map<Integer, Integer> map = ...;
map.put(1, 1);
map.put(2, 2);
map.put(3, 3);
map.put(4, 4);
Is this code...
for (Integer i : map.keySet()) System.out.println(i);
for (Integer i : map.values()) System.out.println(i);
...guaranteed print the same same sequence twice?
If not, are there any guarantees in for example java.util.HashMap?

No, there is no guarantee, although in practice it will happen (there's no good reason for the map to use a different iterator for the keys and values).
If you want to guarantee iteration order, iterate the entrySet():
for (Map.Entry<Integer,Integer> entry : map.entrySet())
// ...
Since you ask about HashMap, note also that any changes to the map will potentially change iteration order, as a result of the mapbeing rehashed.

No, not guaranteed. One is Set and one is Collection, neither guarantee the order.
If you would like to keep order. May be LinkedHashMap() with entrySet() help you.

Yes. Sort of. You can use a subclass of SortedMap, i.e. TreeMap. That will keep keys in a natural order. (or you can give it a specific comparator). But when you use tree map, you HAVE to make sure the compareTo method "must be consistent with equals". Read the javadocs for more details. But in short, yes, you CAN sort a map.

Related

Java: Check if a Key is contained in two HashMap

Is there a way to search and get a subset of keys that are contained in two HashMap objects?
Until now I have always made an iteration from a hashmap and looking for matches in the second.
I just wanted to know if there was a smarter way to do this comparison.
How about
List<String> listOne = new ArrayList<String>(mapOne.keySet());
List<String> listTwo = new ArrayList<String>(mapTwo.keySet());
List<String> listThree = new ArrayList<String>(listTwo);
listThree.retainAll(listOne);
Or
Commons Collections
CollectionUtils.intersection(java.util.Collection a, java.util.Collection b)
There is no way to do that in a complexity less than O(N). The only thing you can do, is to iterate the smallest hashmap.
Another thing you could do is to use the key sets of the hashmaps and use the method retainAll, which perform the intersection for you, but the complexity doesn't change.
Use a HashSet. If your use case needs to have (key, value) pairs, then maintain a HashMap and a HashSet both, and whenever a key is inserted in the HashMap, insert it in the HashSet as well. Otherwise, just maintain a HashSet.
Then you can use retainAll() function to find the intersection of the two sets.
HashSet intersection = hashSet1.retainAll(hashSet2);
The time complexity will be O(n) amortised. This is almost the same as that of what you are doing, but this would make your code much cleaner and readable.
Note that you can maintain a List instead of Set and call the retainAll() method of list. However, retainAll() of List will run in O(n^2) complexity, because the contains() method of List runs in O(n) whereas contains() of HashSet runs in O(1) amortised.
You can create the newMap by removing all keys using removeAll as shown below with inlin comments:
Map<String, String> map1 = new HashMap<>();
Map<String, String> map2 = new HashMap<>();
Set<Entry<String, String>> set1 = map1.entrySet();//get the entries from Map1
set1.removeAll(map2.entrySet());/remove all matched entries mateched in map2
Map<String, String> newMap = set1.stream().//convert set1 to Map using stream
collect(Collectors.toMap(Entry::getKey, Entry::getValue));
This example uses Map<String, String>, but can be applied to any types (of course for custom classes, you need to override equals() and hashcode() methods from java.lang.Object).
Probably not the most efficient way to do it, but this Java 8 one-liner works
Map<Integer,Integer> mapA = ..... // your first map
Map<Integer,Integer> mapB = ..... // your second map
List<Integer> keys = mapA.entrySet().stream().filter((v) -> mapB.containsKey(v.getKey()))
.map(v -> v.getKey()).collect(Collectors.toList());

How to remove first element from a TreeMap?

I need to implement a container which contains maximum 32 values where elements are sorted by key. In C++ it's kinda easy, cause every map is sorted by it's key, in Java I'm not that sure.
So I read some and came with a TreeMap.
How to efficently remove the oldest element from a TreeMap (the first one)?
Thanks!
You said
The key here is a 'sequenceNumber' which is being incremented in the same loop.
By TreeMap documentation it states
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.
So you can easily remove the first element after sorted.
Example:
TreeMap<Integer, String> map = new TreeMap<>();
map.put(1, "ac");
map.put(2, "ef");
map.put(3, "bd");
map.remove(map.firstKey());
Use LinkedHashMap, which has method removeEldestEntry.

HashMap messes up the order of its own elements [duplicate]

This question already has answers here:
Difference between HashMap, LinkedHashMap and TreeMap
(17 answers)
Closed 4 years ago.
Simple as the title, I searched it up already, and I didn't find anything about this issue, I'm pretty sure I just misunderstood how a HashMap works with its own elements.
Super-simplest code:
HashMap<String, Integer> map = new HashMap<String, Integer>();
map.put("first key", 1);
map.put("second key", 2);
map.put("third key", 3);
System.out.println(map.toString());
What does the println() method show?
It shows this:
{third key=3, first key=1, second key=2}
I tough the HashMap stored elements as the programmer put them in.
Even a sorting would sort would place these elements as I put them in origin.
I tried changing the words and similar things happen(only the positions changed, but they were "wrong" anyway). :/
Do you know why?
Thanks in advance :/
EDIT: Rohit Jain is actually the first that answered me as comment, and you guys told me about LinkedHashMap, so you helped me to solve, thank you very much :)
If you want to iterate over your keys by insertion order you need to use a LinkedHashMap instead. The HashMap documentation clearly 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.
You are looking for LinkedHashMap which retains insertion order.
HashMap does not guarantee ordering of any kind.
From the java docs:
This class makes no guarantees as to the order of the map
You can use LinkedHashMap if you want to maintain order.
http://docs.oracle.com/javase/7/docs/api/java/util/HashMap.html
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.
HashMap doesn't preserve order:
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. --javadoc
You want LinkedHashMap:
LinkedHashMap<String, Integer> map = new LinkedHashMap<String, Integer>();
map.put("first key", 1);
map.put("second key", 2);
map.put("third key", 3);
System.out.println(map.toString());
output:
{first key=1, second key=2, third key=3}
If all you care about is the toString, you could also use TreeMap.
There are different Map types, giving different guarantees about their key order (see this).
HashMap: Undefined ordering of its elements.
LinkedHashMap: Order defined by insertion.
TreeMap: Order defined by the compareTo() method of their elements.
So, HashMap makes no guarantee about it's iteration order. Once you insert another element, you will get a different ordering. From what you described a LinkedHashMap might be what you need.

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.

Java HashMap and underlying values() collection

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.

Categories