按值对 Map 进行排序

原文地址:http://www.programcreek.com/2013/03/java-sort-map-by-value/

在 Java 中,我们可以使用 TreeMap 类按键对 Map 进行排序,这个类是非常方便的。然而,有时候我们需要按照它的值对 Map 进行排序。 如何通过其值排序 Map 是 Java 程序员最常问的问题。在这篇文章中,我将找出一个最好的方式来解决这个问题。

1. 粗暴的方式

以下是排序 <String,Integer> 键值对的解决方案,经常用于计数单词的频率。

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 进行排序。 当创建 TreeMap 时,我们给它一个比较器。比较器接受字符串,并比较定字符串键的值。

这个方法运行良好,但仅适用于排序 String 和 Integer 键值对。 如果我们要用其他类型的键值对进行排序时,则需要重写。

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;
}

results matching ""

    No results matching ""