as I know keyset() doesn't guarantee any particular order, however does values() get same order as keyset()?
how about linkedhashmap? seems it can provide a consistent order keyset, assume that it also get a same order values()?
There are absolutely no promises about order in hash tables.
The best way to iterate through any java Map is to use the idiom:
for(Map.Entry<K,V> e : map.entrySet()){
K theKey = e.getKey();
V theValue = e.getValue();
// do something with them!
}
This idiom makes the question irrelevant as you are going through entries in the map in the form of key, value pairs.
As already noted, there is no order guarantees except for SortedMaps or LinkedHashMap and the like. If you have a total ordering on your keys, use a SortedMap: always model your problem explicitly.
Related
I honestly tried to look at a lot of posts but I am not sure what is the correct way of getting a specific key from a ConcurrentHashMap.
How to get the first key in a ConcurrentHashMap?
How to get the key on first encounter of a certain value?
How to update the value of a specific key?
Okay, lets tackle these questions one by one:
1) You cannot. A ConcurrentHashMap has no order. There is no "first" and no "last".
2) A ConcurrentHashMap provides an entrySet which is "weakly consistent", so that if the content of the Map changes during iteration you might see the changes, you might not:
public static <K, V> Optional<K> getKeyForVal(final V val, final Map<K, V> map) {
return map.entrySet().stream()
.filter(e -> e.getValue().equals(val))
.map(Map.Entry::getKey)
.findFirst();
}
Again, there is no "first" this is just the first one encountered during iteration.
3) This is easy, just add the same key -> value pair again, this will update the value for a particular key.
So the main takeaway here is that a ConcurrentHashMap has no order. The order of iteration over a ConcurrentHashMap is undefined and may even change between different iterations. There is no "first", no "last".
Something like ConcurrentSkipListMap does have an ordering, it's sorted by the order of the keys as defined by a Comparator. So that would have a "first" and a "last" element.
I need a data structure that provides key-value mappings, like a Map, but that also allows me to fetch the key based on an (int) index (e.g. myKey = myDS.get(index)), without having to iterate over the data structure to get the key at the desired index.
I thought of using LinkedHashMap, but I don't see a way to get the key at a given index. Am I missing something in LinkedHashMap? Or is there another data structure I can use?
EDIT:
This is not a duplicate. The correct answer to the other question is to use some sort of SortedMap; however, that is not the correct answer to this question, since I'd like to be able to retrieve an Entry from the data structure via an Integer index, which is not supported in any Java library.
LinkedHashMap provides a hash table/doubly linked list implementation of the Map interface. Since it extends HashMap, it's still backed by an array, but there is also a doubly-linked list of Entry objects to ensure that the iteration order is predictable.
So, basically what it means is that when you iterate through the map like so:
for (Map.Entry<keyType,valueType>> entry : linkedHashMap.entrySet())
{
System.out.println("Key: " + entry.getKey().toString() +
" Value: " + entry.getValue.toString());
}
it will print in the order that you added the keys, as opposed to a non-linked Map, which will not print in insertion order. You cannot access the elements of the array like you want to, because the array that backs the hash is not in order. Only the doubly linked list is ordered.
Solution:
What you are looking for is a LinkedMap from Apache Commons.
AFAIK, there is no single data structure that will do this. There is certainly not one in the standard Java collection suite.
Also LinkedHashMap is not the solution because you cannot efficiently index a LinkedHashMap.
If you want to do index-based lookup as well as keep-based lookup, solution needs to be a combination of two data structures.
A Map<Key, Value> and an ArrayList<Value> is the simpler approach, but it has a couple of problems:
- Insertion and deletion of values from the ArrayList is expensive, unless you are inserting / deleting at the tail end of the list.
- Insertion and deletion makes the list positions unstable,.
If you want stable indexes and scalable insertion and deletion, then you need a Map<Key, Value> and a Map<Integer, Value> ... and a way to manage (i.e. recycle) the index values.
The Apache Commons LinkedMap class is a possible solution, except that it suffers from the problem that index values are not stable in the face of insertions and deletions.
How about using:
Map<String, String> map = new LinkedHashMap<String, String>();
List<Entry<String, String>> mapAsList = new ArrayList<Map.Entry<String,String>>(map.entrySet());
mapAsList.get(index);
I do not believe there is a collection for this; collections are either based on the idea that you want to know exactly where an element is (lists) or that you want quick access based on some key or criteria (maps); doing both would be very resource-intensive to maintain.
Of course, you can make something like this, as rocketboy's answer suggests, but I'm guessing it's not really possible to make efficient.
There is no direct DS in the standard Java Collections API to provide a indexed map. However, the following should let you achieve the result:
// An ordered map
Map<K, V> map = new LinkedHashMap<K, V>();
// To create indexed list, copy the references into an ArrayList (backed by an array)
List<Entry<K, V>> indexedList = new ArrayList<Map.Entry<K, V>>(map.entrySet());
// Get the i'th term
<Map.Entry<K,V>> entry = indexedList.get(index);
K key = entry.getKey();
V value = entry.getValue();
You might still want to retain the concerns of data persistence in the map separate from the retrieval.
Update:
Or use LinkedMap from Apache Commons as suggested by Steve.
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 have a hashtable, which contains strings for example, when I use put method as below
hashtable.put("1","A");
hashtable.put("1","B");
hashtable.put("1","C");
hashtable.put("1","D");
hashtable.put("1","E");
Then when I try to print it back it doesn't print in same order, Any one knows why would something like this happen?
Collection c = ht.values();
Iterator itr = c.iterator();
while(itr.hasNext())
System.out.println(itr.next());
Thanks
Max
A Hashtable does not guarantee any kind of ordering.
If you want to preserve insertion order, use a LinkedHashMap. However, the contract is slightly different than a Hashtable in that it allows null elements.
you should use LinkedHashMap if you want to print items in order.
That is simply the property of a hash table -- it makes no guarantee about ordering. Do you want to use a LinkedHashMap instead?
HashTable doesnot keep order.It will print randomly.You should go for LinkedHashMap.You can use LinkedHashMap in the same manner as you did for HashMap.Just put LinkedHashMap in place of HashMap.LinkedHashMap keeps the order of data in which you enter into it.
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.