在Java中,我们用TreeMap 类进行map的按Key排序。这个类实用起来很方便。但是有时候我们需要对一个map进行按值排序。如何对map进行按值排序,是Java开发者常问的问题,在这篇文章中,我将编写最好的按值排序方法。
1.本地方法
以下是对<String,Integer>的map的排序解决方法,这通常用于计算单词出现的频率。
import java.util.Comparator;
import java.util.HashMap;
import java.util.TreeMap;
public class SortMapByValue {
public static void main(String[] args) {
HashMap<String, Integer> map = new HashMap<String, Integer>();
map.put("a", 10);
map.put("b", 30);
map.put("c", 50);
map.put("d", 40);
map.put("e", 20);
System.out.println(map);
TreeMap<String, Integer> sortedMap = sortMapByValue(map);
System.out.println(sortedMap);
}
public static TreeMap<String, Integer> sortMapByValue(HashMap<String, Integer> map){
Comparator<String> comparator = new ValueComparator(map);
//TreeMap is a map sorted by its keys.
//The comparator is used to sort the TreeMap by keys.
TreeMap<String, Integer> result = new TreeMap<String, Integer>(comparator);
result.putAll(map);
return result;
}
}
下面是comparator类的具体实现:
// a comparator that compares Strings
class ValueComparator implements Comparator<String>{
HashMap<String, Integer> map = new HashMap<String, Integer>();
public ValueComparator(HashMap<String, Integer> map){
this.map.putAll(map);
}
@Override
public int compare(String s1, String s2) {
if(map.get(s1) >= map.get(s2)){
return -1;
}else{
return 1;
}
}
}
在这个解决方案中,我们利用TreeMap对Map进行排序,当创建Map时候,我们给它一个比较器。这个比较器接受字符串,比较它们作为key在map中映射的值。
这个方法运行良好,但是仅仅适用String和Integer的对。如果你想对一个包含其他类型的键值的Map进行排序,需要重写它。因此一个通用的方法更好。
2. 更通用的解决办法
我们可以忽略泛型,让方法适用于任何类型,如下:
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
public class Solution {
public static void main(String[] args) {
HashMap<String, Integer> map = new HashMap<String, Integer>();
map.put("a", 10);
map.put("b", 30);
map.put("c", 50);
map.put("d", 40);
map.put("e", 20);
System.out.println(map);
Map sortedMap = sortByValue(map);
System.out.println(sortedMap);
}
public static Map sortByValue(Map unsortedMap) {
Map sortedMap = new TreeMap(new ValueComparator(unsortedMap));
sortedMap.putAll(unsortedMap);
return sortedMap;
}
}
class ValueComparator implements Comparator {
Map map;
public ValueComparator(Map map) {
this.map = map;
}
public int compare(Object keyA, Object keyB) {
Comparable valueA = (Comparable) map.get(keyA);
Comparable valueB = (Comparable) map.get(keyB);
return valueB.compareTo(valueA);
}
}
这个解决方法不是类型安全的,我们需要一个类型安全的和更通用的解决方法。
3. 用通用的类型
public class SortMapByValue {
public static void main(String[] args) {
// <String, Integer> Map
HashMap<String, Integer> map = new HashMap<String, Integer>();
map.put("a", 10);
map.put("b", 30);
map.put("c", 50);
map.put("d", 40);
map.put("e", 20);
System.out.println(map);
Comparator<String> comparator = new ValueComparator<String, Integer>(map);
TreeMap<String, Integer> result = new TreeMap<String, Integer>(comparator);
result.putAll(map);
System.out.println(result);
// <Integer, Integer> Map
HashMap<Integer, Integer> map2 = new HashMap<Integer, Integer>();
map2.put(1, 10);
map2.put(2, 30);
map2.put(3, 50);
map2.put(4, 40);
map2.put(5, 20);
System.out.println(map2);
Comparator<Integer> comparator2 = new ValueComparator<Integer, Integer>(map2);
TreeMap<Integer, Integer> result2 = new TreeMap<Integer, Integer>(comparator2);
result2.putAll(map2);
System.out.println(result2);
}
}
// a comparator using generic type
class ValueComparator<K, V extends Comparable<V>> implements Comparator<K>{
HashMap<K, V> map = new HashMap<K, V>();
public ValueComparator(HashMap<K, V> map){
this.map.putAll(map);
}
@Override
public int compare(K s1, K s2) {
return -map.get(s1).compareTo(map.get(s2));//descending order
}
}
4.另外一种利用泛型的方法
public static <K, V extends Comparable<? super V>> Map<K, V> sortByValue(Map<K, V> map) {
List<Map.Entry<K, V>> list = new LinkedList<>(map.entrySet());
Collections.sort(list, new Comparator<Map.Entry<K, V>>() {
@Override
public int compare(Map.Entry<K, V> e1, Map.Entry<K, V> e2) {
return (e1.getValue()).compareTo(e2.getValue());
}
});
Map<K, V> result = new LinkedHashMap<>();
for (Map.Entry<K, V> entry : list) {
result.put(entry.getKey(), entry.getValue());
}
return result;
}