I have a Map that has strings for both keys and values.
Data is like following:
"question1", "1"
"question9", "1"
"question2", "4"
"question5", "2"
I want to sort the map based on its keys. So, in the end, I will have question1, question2, question3
....and so on.
Eventually, I am trying to get two strings out of this Map.
Right now I have the following:
Iterator it = paramMap.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pairs = (Map.Entry) it.next();
questionAnswers += pairs.getKey() + ",";
}
This gets me the questions in a string but they are not in order.
This question is related to
java
dictionary
hashmap
Just use TreeMap
new TreeMap<String, String>(unsortMap);
Be aware that the TreeMap is sorted according to the natural ordering of its 'keys'
In Java 8 you can also use .stream().sorted():
myMap.keySet().stream().sorted().forEach(key -> {
String value = myMap.get(key);
System.out.println("key: " + key);
System.out.println("value: " + value);
}
);
Provided you cannot use TreeMap
, in Java 8 we can make use of toMap() method in Collectors
which takes following parameters:
Java 8 Example
Map<String,String> sample = new HashMap<>(); // push some values to map
Map<String, String> newMapSortedByKey = sample.entrySet().stream()
.sorted(Map.Entry.<String,String>comparingByKey().reversed())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
Map<String, String> newMapSortedByValue = sample.entrySet().stream()
.sorted(Map.Entry.<String,String>comparingByValue().reversed())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1,e2) -> e1, LinkedHashMap::new));
We can modify the example to use custom comparator and to sort based on keys as:
Map<String, String> newMapSortedByKey = sample.entrySet().stream()
.sorted((e1,e2) -> e1.getKey().compareTo(e2.getKey()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1,e2) -> e1, LinkedHashMap::new));
Use a TreeMap!
A good solution is provided here. We have a HashMap
that stores values in unspecified order. We define an auxiliary TreeMap
and we copy all data from HashMap into TreeMap using the putAll
method. The resulting entries in the TreeMap are in the key-order.
Just in case you don't wanna use a TreeMap
public static Map<Integer, Integer> sortByKey(Map<Integer, Integer> map) {
List<Map.Entry<Integer, Integer>> list = new ArrayList<>(map.entrySet());
list.sort(Comparator.comparingInt(Map.Entry::getKey));
Map<Integer, Integer> sortedMap = new LinkedHashMap<>();
list.forEach(e -> sortedMap.put(e.getKey(), e.getValue()));
return sortedMap;
}
Also, in-case you wanted to sort your map on the basis of values
just change Map.Entry::getKey
to Map.Entry::getValue
Use a TreeMap
. This is precisely what it's for.
If this map is passed to you and you cannot determine the type, then you can do the following:
SortedSet<String> keys = new TreeSet<>(map.keySet());
for (String key : keys) {
String value = map.get(key);
// do something
}
This will iterate across the map in natural order of the keys.
Technically, you can use anything that implements SortedMap
, but except for rare cases this amounts to TreeMap
, just as using a Map
implementation typically amounts to HashMap
.
For cases where your keys are a complex type that doesn't implement Comparable or you don't want to use the natural order then TreeMap
and TreeSet
have additional constructors that let you pass in a Comparator
:
// placed inline for the demonstration, but doesn't have to be a lambda expression
Comparator<Foo> comparator = (Foo o1, Foo o2) -> {
...
}
SortedSet<Foo> keys = new TreeSet<>(comparator);
keys.addAll(map.keySet());
Remember when using a TreeMap
or TreeSet
that it will have different performance characteristics than HashMap
or HashSet
. Roughly speaking operations that find or insert an element will go from O(1) to O(Log(N)).
In a HashMap
, moving from 1000 items to 10,000 doesn't really affect your time to lookup an element, but for a TreeMap
the lookup time will be about 3 times slower (assuming Log2). Moving from 1000 to 100,000 will be about 6 times slower for every element lookup.
We can also sort the key by using Arrays.sort method.
Map<String, String> map = new HashMap<String, String>();
Object[] objArr = new Object[map.size()];
for (int i = 0; i < map.size(); i++) {
objArr[i] = map.get(i);
}
Arrays.sort(objArr);
for (Object str : objArr) {
System.out.println(str);
}
List<String> list = new ArrayList<String>();
Map<String, String> map = new HashMap<String, String>();
for (String str : map.keySet()) {
list.add(str);
}
Collections.sort(list);
for (String str : list) {
System.out.println(str);
}
To sort a Map<K, V>
by key, putting keys into a List<K>
:
List<K> result = map.keySet().stream().sorted().collect(Collectors.toList());
To sort a Map<K, V>
by key, putting entries into a List<Map.Entry<K, V>>
:
List<Map.Entry<K, V>> result =
map.entrySet()
.stream()
.sorted(Map.Entry.comparingByKey())
.collect(Collectors.toList());
Last but not least: to sort strings in a locale-sensitive manner - use a Collator (comparator) class:
Collator collator = Collator.getInstance(Locale.US);
collator.setStrength(Collator.PRIMARY); // case insensitive collator
List<Map.Entry<String, String>> result =
map.entrySet()
.stream()
.sorted(Map.Entry.comparingByKey(collator))
.collect(Collectors.toList());
This code can sort a key-value map in both orders i.e. ascending and descending.
<K, V extends Comparable<V>> Map<K, V> sortByValues
(final Map<K, V> map, int ascending)
{
Comparator<K> valueComparator = new Comparator<K>() {
private int ascending;
public int compare(K k1, K k2) {
int compare = map.get(k2).compareTo(map.get(k1));
if (compare == 0) return 1;
else return ascending*compare;
}
public Comparator<K> setParam(int ascending)
{
this.ascending = ascending;
return this;
}
}.setParam(ascending);
Map<K, V> sortedByValues = new TreeMap<K, V>(valueComparator);
sortedByValues.putAll(map);
return sortedByValues;
}
As an example:
Map<Integer,Double> recommWarrVals = new HashMap<Integer,Double>();
recommWarrVals = sortByValues(recommWarrVals, 1); // Ascending order
recommWarrVals = sortByValues(recommWarrVals,-1); // Descending order
Assuming TreeMap is not good for you (and assuming you can't use generics):
List sortedKeys=new ArrayList(yourMap.keySet());
Collections.sort(sortedKeys);
// Do what you need with sortedKeys.
If you already have a map and would like to sort it on keys, simply use :
Map<String, String> treeMap = new TreeMap<String, String>(yourMap);
A complete working example :
import java.util.HashMap;
import java.util.Set;
import java.util.Map;
import java.util.TreeMap;
import java.util.Iterator;
class SortOnKey {
public static void main(String[] args) {
HashMap<String,String> hm = new HashMap<String,String>();
hm.put("3","three");
hm.put("1","one");
hm.put("4","four");
hm.put("2","two");
printMap(hm);
Map<String, String> treeMap = new TreeMap<String, String>(hm);
printMap(treeMap);
}//main
public static void printMap(Map<String,String> map) {
Set s = map.entrySet();
Iterator it = s.iterator();
while ( it.hasNext() ) {
Map.Entry entry = (Map.Entry) it.next();
String key = (String) entry.getKey();
String value = (String) entry.getValue();
System.out.println(key + " => " + value);
}//while
System.out.println("========================");
}//printMap
}//class
Using Java 8:
Map<String, Integer> sortedMap = unsortMap.entrySet().stream()
.sorted(Map.Entry.comparingByKey())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
(oldValue, newValue) -> oldValue, LinkedHashMap::new));
Using the TreeMap
you can sort the map.
Map<String, String> map = new HashMap<>();
Map<String, String> treeMap = new TreeMap<>(map);
for (String str : treeMap.keySet()) {
System.out.println(str);
}
Source: Stackoverflow.com