我对Java比较陌生,经常发现需要对值进行Map<Key,Value>排序。

由于这些值不是唯一的,我发现自己将keySet转换为一个数组,并使用自定义比较器通过数组排序对该数组进行排序,该比较器根据与该键关联的值进行排序。

有没有更简单的方法?


当前回答

这还有一个额外的好处,即可以使用Java8进行升序或降序排序

import static java.util.Comparator.comparingInt;
import static java.util.stream.Collectors.toMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Collectors;
import java.util.stream.Stream;

class Utils {
    public static Map<String, Integer> sortMapBasedOnValues(Map<String, Integer> map, boolean descending) {
        int multiplyBy = (descending) ? -1: 1;
        Map<String, Integer> sorted =  map.entrySet().stream()
                .sorted(comparingInt(e -> multiplyBy * e.getValue() ))
                .collect(toMap(
                        Map.Entry::getKey, 
                        Map.Entry::getValue,
                        (a, b) -> { throw new AssertionError();},
                        LinkedHashMap::new
                    ));
        return sorted;
    }
}

其他回答

创建自定义比较器,并在创建新的TreeMap对象时使用它。

class MyComparator implements Comparator<Object> {

    Map<String, Integer> map;

    public MyComparator(Map<String, Integer> map) {
        this.map = map;
    }

    public int compare(Object o1, Object o2) {

        if (map.get(o2) == map.get(o1))
            return 1;
        else
            return ((Integer) map.get(o2)).compareTo((Integer)     
                                                            map.get(o1));

    }
}

在主函数中使用以下代码

    Map<String, Integer> lMap = new HashMap<String, Integer>();
    lMap.put("A", 35);
    lMap.put("B", 75);
    lMap.put("C", 50);
    lMap.put("D", 50);

    MyComparator comparator = new MyComparator(lMap);

    Map<String, Integer> newMap = new TreeMap<String, Integer>(comparator);
    newMap.putAll(lMap);
    System.out.println(newMap);

输出:

{B=75, D=50, C=50, A=35}

在Java 8及以上版本中对任何地图进行排序的简单方法

Map<String, Object> mapToSort = new HashMap<>();

List<Map.Entry<String, Object>> list = new LinkedList<>(mapToSort.entrySet());

Collections.sort(list, Comparator.comparing(o -> o.getValue().getAttribute()));

HashMap<String, Object> sortedMap = new LinkedHashMap<>();
for (Map.Entry<String, Object> map : list) {
   sortedMap.put(map.getKey(), map.getValue());
}

如果您使用的是Java 7及以下版本

Map<String, Object> mapToSort = new HashMap<>();

List<Map.Entry<String, Object>> list = new LinkedList<>(mapToSort.entrySet());

Collections.sort(list, new Comparator<Map.Entry<String, Object>>() {
    @Override
    public int compare(Map.Entry<String, Object> o1, Map.Entry<String, Object> o2) {
       return o1.getValue().getAttribute().compareTo(o2.getValue().getAttribute());      
    }
});

HashMap<String, Object> sortedMap = new LinkedHashMap<>();
for (Map.Entry<String, Object> map : list) {
   sortedMap.put(map.getKey(), map.getValue());
}

使用Guava库:

public static <K,V extends Comparable<V>>SortedMap<K,V> sortByValue(Map<K,V> original){
    var comparator = Ordering.natural()
            .reverse() // highest first
            .nullsLast()
            .onResultOf(Functions.forMap(original, null))
            .compound(Ordering.usingToString());
    return ImmutableSortedMap.copyOf(original, comparator);
}

Java 8提供了一个新的答案:将条目转换为流,并使用Map中的比较器组合符。条目:

Stream<Map.Entry<K,V>> sorted =
    map.entrySet().stream()
       .sorted(Map.Entry.comparingByValue());

这将允许您使用按值升序排序的条目。如果您想要递减值,只需反转比较器:

Stream<Map.Entry<K,V>> sorted =
    map.entrySet().stream()
       .sorted(Collections.reverseOrder(Map.Entry.comparingByValue()));

如果这些值不可比较,则可以传递显式比较器:

Stream<Map.Entry<K,V>> sorted =
    map.entrySet().stream()
       .sorted(Map.Entry.comparingByValue(comparator));

然后,您可以继续使用其他流操作来使用数据。例如,如果要在新地图中显示前10名:

Map<K,V> topTen =
    map.entrySet().stream()
       .sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
       .limit(10)
       .collect(Collectors.toMap(
          Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));

上面看到的LinkedHashMap按插入顺序迭代条目。

或打印到System.out:

map.entrySet().stream()
   .sorted(Map.Entry.comparingByValue())
   .forEach(System.out::println);

从…起http://www.programmersheaven.com/download/49349/download.aspx

private static <K, V> Map<K, V> sortByValue(Map<K, V> map) {
    List<Entry<K, V>> list = new LinkedList<>(map.entrySet());
    Collections.sort(list, new Comparator<Object>() {
        @SuppressWarnings("unchecked")
        public int compare(Object o1, Object o2) {
            return ((Comparable<V>) ((Map.Entry<K, V>) (o1)).getValue()).compareTo(((Map.Entry<K, V>) (o2)).getValue());
        }
    });

    Map<K, V> result = new LinkedHashMap<>();
    for (Iterator<Entry<K, V>> it = list.iterator(); it.hasNext();) {
        Map.Entry<K, V> entry = (Map.Entry<K, V>) it.next();
        result.put(entry.getKey(), entry.getValue());
    }

    return result;
}