This question already has answers here:
How to Maintain order of insertion [duplicate]
(3 answers)
Closed 9 years ago.
I have a list which I convert to a map to do some work. After that, i convert the map back again to a list, but this time the order is random. I need the same initial order retained in my second list.
the obvious reason is that a HashMap doesn't maintain order. But I need to do something so that it does. I cannot change the Map implementation.How can I do that ?
Consider the given code:
import java.util.*;
public class Dummy {
public static void main(String[] args) {
System.out.println("Hello world !");
List<String> list = new ArrayList<String>();
list.add("A");list.add("B");list.add("C");
list.add("D");list.add("E");list.add("F");
Map<String,String> map = new HashMap<String, String>();
for(int i=0;i<list.size();i=i+2)
map.put(list.get(i),list.get(i+1));
// Use map here to do some work
List<String> l= new ArrayList<String>();
for (Map.Entry e : map.entrySet()) {
l.add((String) e.getKey());
l.add((String) e.getValue());
}
}
}
For ex - Initially, when I printed the list elements, it printed out
A B C D E F
Now, when I print the elements of List l, it printed out
E F A B C D
HashMap itself doesn't maintain insertion order - but LinkedHashMap does, so use that instead.
As documented... HashMap:
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.
And 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).
Use LinkedHashMap instead of HashMap to maintain order.
Map<String,String> map = new LinkedHashMap<String, String>();
Why can't you change the Map implementation (to LinkedHashMap for example)?
If there's a logical ordering, you could sort the List with a custom Comparator.
HashMap doesn't preserve order of insertion
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.
Use LinkedHashMap if you want to preserve order of keys
Consider making your items sortable. In the case of strings, there is already a natural ordering; alphabetical. You can make objects that use the sortable class, and therefore you can use sorting algorithms to put these objects in a nice order, no matter what order you get them in from hash!
It's time for a LinkedHashMap, it is meant exactly to preserve insertion order.
Mind that even a TreeMap exists, which allows you to keep your desired order by using Comparable interface. It is not an hash map anymore, but a tree.
If you truly are unable to switch to another Map implementation (LinkedHashMap is exactly what you want), then the only other possibility is to retain the original List, and use it to create the new List from the Map.
public <T> List<T> listFromMapInOrder(final Map<T, T> map, final List<T> order) {
List<T> result = new ArrayList<T>();
for (T key : order) {
if (map.containsKey(key)) {
result.add(key);
result.add(map.get(key));
}
}
return result;
}
But I would refactor the code until it was possible to switch to a LinkedHashMap.
Related
I know HashSet internally work as HashMap and HashMap internally use LinkedList as FIFO etc. So my Question is when I insert values in StudentRecord class object in pattern like..
StudentsRecord record=new StudentsRecord(1, "Pramod", "UNA");
StudentsRecord record2=new StudentsRecord(2, "Pankaj","Lucknow");
StudentsRecord record3=new StudentsRecord(3, "Santosh","Chennai");
HashSet<StudentsRecord> set=new HashSet<StudentsRecord>();
set.add(record);
set.add(record2);
set.add(record3);
Iterator<StudentsRecord> iterator=set.iterator();
while(iterator.hasNext())
{
StudentsRecord result=(StudentsRecord)iterator.next();
System.out.println(result.getId()+","+result.getName()+","+result.getAddress());
}
After this why my result does not follow FIFO or LIFO order pattern?
My Output is:
3,Santosh,Chennai
1,Pramod,UNA
2,Pankaj,Lucknow
Use LinkedHashSet instead of HashSet. because LinkedHashSet maintains insertion order.
public static void main(String[] args) {
StudentsRecord record=new StudentsRecord(1, "Pramod", "UNA");
StudentsRecord record2=new StudentsRecord(2, "Pankaj","Lucknow");
StudentsRecord record3=new StudentsRecord(3, "Santosh","Chennai");
Set<StudentsRecord> set=new LinkedHashSet<StudentsRecord>();
set.add(record);
set.add(record2);
set.add(record3);
Iterator<StudentsRecord> iterator=set.iterator();
while(iterator.hasNext())
{
StudentsRecord result=(StudentsRecord)iterator.next();
System.out.println(result.getId()+","+result.getName()+","+result.getAddress());
}
}
LinkedHashMap can be used for this purpose.
It is same as HashMap, except that when you iterate over it, it presents the items in the insertion order.
Basically it preserves the insertion order.
from JavaDoc
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.
LinkedHashSet will preserve insertion order for you.
Since none of the other answers actually answered "why":
HashMap stores objects into buckets, and then only uses the lists in the bucket. This is how it is able to find objects fast, as it can go straight to the correct bucket and then only needs to scan the entries inside that bucket.
In this example 3. has been added into an earlier bucket than 2 or 3 and as a result comes back in a different order.
HashMap and HashSet should never be relied upon to provide any particular ordering. You can use LinkedHashMap to retain insertion order or TreeMap to sort the entries.
This question already has answers here:
Is the order of values retrieved from a HashMap the insertion order
(6 answers)
Closed 9 years ago.
I have a Map with values and get a Set using Map.keySet method.
In this code:
Map<String, String> map = new HashMap<>();
map.put("1", "a");
map.put("2", "b");
map.put("3", "c");
Set<String> set = map.keySet();
for (int i = 0; i < 5; i++) {
for (String key : set) {
System.out.println(key);
}
}
am I guaranteed to get
1
2
3
written out every time? Where is this guarantee written down ? In Javadoc?
EDIT: Actually I don't care about the insertion order, but I care about the fact that using for-each loop on a set will produce the same result over and over, providing that the undelying map does not change (I don't call put, remove).
No, you are not. But you can use LinkedHashMap (http://docs.oracle.com/javase/6/docs/api/java/util/LinkedHashMap.html) and then you will be guaranteed.
LinkedHashMap for order of additionn (put), and TreeMap (interface SortedMap) for order of keys.
Unfortunately the docs for HashMap state that keySet() method does not return a SortedSet, it just returns a Set, for which the ordering is not guaranteed.
See HashMap.keySet()
Read, in particular: It makes no guarantees as to the iteration order of the set; in particular, it does not guarantee that the order will remain constant over time.
Use LinkedHashMap if you want to retrieve in order in which you put key .
No you're not guaranteed a specific order, unless you use a HashMap which implements a custom set that can give you this guarantee. The Set the HashMap gives you back have an Iterator() method which iterates over the elements in "no particular order".
Read the java documentation: http://docs.oracle.com/javase/1.5.0/docs/api/java/util/Set.html#iterator()
If you want the guarantee that the elements are iterated over in-order, i.e. ascending order, use something that implements SortedMap like TreeMap.
TreeMap Documentation: http://docs.oracle.com/javase/6/docs/api/java/util/TreeMap.html
On this page you find the getSet() method which says "The set's iterator returns the keys in ascending order".
I'm creating a new Map and pushing strings into it (no big deal) -but I've noticed that the strings are being re-ordered as the map grows. Is it possible to stop this re-ordering that occurs so the items in the map retain the order the were put in with?
Map<String,String> x = new HashMap<String, String>();
x.put("a","b");
x.put("a","c");
x.put("a","d");
x.put("1","2");
x.put("1","3");
x.put("1","4");
//this shows them out of order sadly...
for (Map.Entry<String, String> entry : x.entrySet()) {
System.out.println("IN THIS ORDER ... " + entry.getValue());
}
If you care about order, you can use a SortedMap. The actual class which implements the interface (at least for most scenarios) is a TreeMap. Alternatively, LinkedHashMap also maintains its order, while still utilizing a hashtable-based container.
You can keep it with LinkedHashMap.
A HashMap in java is not sorted http://download.oracle.com/javase/1,5.0/docs/api/java/util/HashMap.html. If you want predictable iteration order use a LinkedHashMap instead: http://download.oracle.com/javase/1.4.2/docs/api/java/util/LinkedHashMap.html
Heres a good discussion on the difference: How is the implementation of LinkedHashMap different from HashMap?
The previous answers are correct in that you should use an implementation of Map that maintains ordering. LinkedHashMap and SortedMap each do these things.
However, the takeaway point is that not all collections maintain order and if order is important to you, you should choose the appropriate implementation. Generic HashMaps do not maintain order, do not claim to do so and cannot be set to do so.
Ok so i am new to these HashMaps but have some idea about LinkedLists and HashMaps.
It would be great if you could give me some simple explanation regarding LinkedHashMap and as in the titile does this mean we are explicitly defining it to be of some type?
A LinkedHashMap is a combination of
hash table and linked list. It has a
predictable iteration order (a la
linked list), yet the retrieval speed
is that of a HashMap. The order of the
iteration is determined by the
insertion order, so you will get the
key/values back in the order that they
were added to this Map. You have to be
a bit careful here, since re-inserting
a key does not change the original
order.
k stand for Key and v for Value.
/*
Simple Java LinkedHashMap example
This simple Java Example shows how to use Java LinkedHashMap.
It also describes how to add something to LinkedHashMap and how to
retrieve the value added from LinkedHashMap.
*/
import java.util.LinkedHashMap;
public class JavaLinkedHashMapExample {
public static void main(String[] args) {
//create object of LinkedHashMap
LinkedHashMap lHashMap = new LinkedHashMap();
/*
Add key value pair to LinkedHashMap using
Object put(Object key, Object value) method of Java LinkedHashMap class,
where key and value both are objects
put method returns Object which is either the value previously tied
to the key or null if no value mapped to the key.
*/
lHashMap.put("One", new Integer(1));
lHashMap.put("Two", new Integer(2));
/*
Please note that put method accepts Objects. Java Primitive values CAN NOT
be added directly to LinkedHashMap. It must be converted to corrosponding
wrapper class first.
*/
//retrieve value using Object get(Object key) method of Java LinkedHashMap class
Object obj = lHashMap.get("One");
System.out.println(obj);
/*
Please note that the return type of get method is an Object. The value must
be casted to the original class.
*/
}
}
/*
Output of the program would be
1
*/
It is a hybrid of two data structures, a LinkedList, where insertion order is preserved by adding elements to the end of a list of nodes which have access to their immediate neighbours, and a HashMap, or a Map that uses an array of bucket Lists, where a modulus division remainder of the key's hashcode() determines the starting bucket to query for the equals() method of the keys that lie in that bucket's list of contents.
The advantage is that you can walk the existing elements in a HashMap in order of insertion, due to the LinkedList nature, and you can quickly jump to the correct bucket in a key lookup (saving a lot of time for a large collection) if you have the key of the element.
This is called generics. k and v must be replaced with the actual type you want to store.
To create a HashMap that maps integers on strings you would write:
LinkedHashMap<Integer,String>
LinkedHashMap keys are similar to ArrayLists or arrays in the way they are stored in the order that they are inserted.
Normal HashMaps are sorted by their hash code.
k = key
v = value
They can be any type.
The biggest difference is LinkedHashMap is ordered. If you use an iterator the keys and values will be in the same order they were added to the map. HashMap has no guarantee of the order they are returned.
Read about Generics in Java on Wikipedia.
I have one Map that contains some names and numbers
Map<String,Integer> abc = new HashMap<String,Integer>();
It works fine. I can put some values in it but when I call it in different class it gives me wrong order. For example:
I putted
abc.put("a",1);
abc.put("b",5);
abc.put("c",3);
Iterator<String> iter = abc.keySet().iterator();
while (iter.hasNext()) {
String name = iter.next();
System.out.println(name);
}
some time it returns the order (b,a,c) and some time (a,c,b).
What is wrong with it? Is there any step that I am missing when I call this map?
Edit:
I changed to HashMap and result is still same
The only thing that's wrong is your expectations. The Map interface makes no guarantees about iteration order, and the HashMap implementation is based on hash functions which means the iteration order is basically random, and will sometimes change completely when new elements are added.
If you want a specific iteration order, you have thee options:
The SortedMap interfaces with its TreeMap implementation - these guarantee an iteration order according to the natural ordering of the keys (or an ordering imposed by a Comparator instance)
The LinkedHashMap class iterates in the order the elements were added to the map.
Use a List instead of a Map - this has a well-defined iteration order that you can influence in detail.
I think you need LinkedHashMap.
A TreeMap will always have keys in their natural order (unless you provide a comparator) If you are seeing the order any differently it will be the way you are looking at the map and what you are doing with it. If in doubt, use a debugger and you will see the order is sorted.
If you wish to get map values in the same order you used to insert them use LinkedHashMap instead.