Java 中 Map 按值排序

在 Java 中对一个 Map 按 Key 排序是很简单的一件事(TreeMap)。但是按 Value 排序的话,却略显麻烦。

在 Java 8 之前,对 Map 按 Value 排序一般有两种方法:

// 1. TreeMap
public class Testing {

    public static void main(String[] args) {
        HashMap<String, Integer> unsortMap = new HashMap<>();
        ValueComparator comparator = new ValueComparator(unsortMap);
        TreeMap<String, Integer> sortedMap = new TreeMap<>(comparator);

        // put {A=9, B=2, C=7, D=1} into unsortMap

        System.out.println("unsorted map: " + unsortMap);
        sortedMap.putAll(unsortMap);
        System.out.println("sorted map: " + sortedMap);
    }
}

class ValueComparator implements Comparator<String> {

    Map<String, Integer> base;

    public ValueComparator(Map<String, Integer> base) {
        this.base = base;
    }

    // this comparator imposes orderings that are inconsistent with equals.
    public int compare(String a, String b) {
        if (base.get(a) >= base.get(b)) {
            return 1;
        } else {
            return -1;
        } // returning 0 would merge keys
    }
}
// output:
// unsorted map: {A=9, B=2, C=7, D=1}
// sorted map: {D=1, B=2, C=7, A=9}
// 2. add every Entry into List, sort the List and then put into LinkedHashMap
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>>() {

        public int compare(Map.Entry<K, V> o1, Map.Entry<K, V> o2) {
            return (o1.getValue()).compareTo(o2.getValue());
        }
    });

    Map<K, V> result = new LinkedHashMap<>();
    for (Map.Entry<K, V> entry : list) {
        result.put(entry.getKey(), entry.getValue());
    }
    return result;
}
// test: same as 1

在 Java 8 中,得益于新特性——Stream 和 Lambda 表达式,对 Map 按 Value 排序可以实现的更加优雅

public static void main(String[] args) {
    Map<String, Integer> unsortMap = new HashMap<>();

    // put {A=9, B=2, C=7, D=1} into unsortMap

    BinaryOperator<Integer> mergeFunction = (u, v) -> {
        throw new IllegalStateException(String.format("Duplicate key %s", u));
    };
    Map<String, Integer> sortedMap = unsortMap.entrySet().stream()
        .sorted(Entry.<String, Integer> comparingByValue().reversed())
        .collect(Collectors.toMap(Entry::getKey, Entry::getValue, mergeFunction, LinkedHashMap::new));

    System.out.println("unsorted map: " + unsortMap);
    System.out.println("sorted map: " + sortedMap);
}
// output:
// unsorted map: {A=9, B=2, C=7, D=1}
// sorted map: {A=9, C=7, B=2, D=1}

核心代码仅 3 行,如果我们再对常用的LinkedHashMap Collector进行封装,代码就看起来更简洁舒服了。

不由感慨 Lambda 大法好~😄


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!