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

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

有没有更简单的方法?


当前回答

这种方法正好能达到目的。(“挫折”是Values必须实现java.util.Comparable接口)

  /**

 * Sort a map according to values.

 * @param <K> the key of the map.
 * @param <V> the value to sort according to.
 * @param mapToSort the map to sort.

 * @return a map sorted on the values.

 */ 
public static <K, V extends Comparable< ? super V>> Map<K, V>
sortMapByValues(final Map <K, V> mapToSort)
{
    List<Map.Entry<K, V>> entries =
        new ArrayList<Map.Entry<K, V>>(mapToSort.size());  

    entries.addAll(mapToSort.entrySet());

    Collections.sort(entries,
                     new Comparator<Map.Entry<K, V>>()
    {
        @Override
        public int compare(
               final Map.Entry<K, V> entry1,
               final Map.Entry<K, V> entry2)
        {
            return entry1.getValue().compareTo(entry2.getValue());
        }
    });      

    Map<K, V> sortedMap = new LinkedHashMap<K, V>();      

    for (Map.Entry<K, V> entry : entries)
    {
        sortedMap.put(entry.getKey(), entry.getValue());

    }      

    return sortedMap;

}

http://javawithswaranga.blogspot.com/2011/06/generic-method-to-sort-hashmap.html

其他回答

map = your hashmap;

List<Map.Entry<String, Integer>> list = new LinkedList<Map.Entry<String, Integer>>(map.entrySet());
Collections.sort(list, new cm());//IMP

HashMap<String, Integer> sorted = new LinkedHashMap<String, Integer>();
for(Map.Entry<String, Integer> en: list){
    sorted.put(en.getKey(),en.getValue());
}

System.out.println(sorted);//sorted hashmap

创建新类

class cm implements Comparator<Map.Entry<String, Integer>>{
    @Override
    public int compare(Map.Entry<String, Integer> a, 
                            Map.Entry<String, Integer> b)
    {
        return (a.getValue()).compareTo(b.getValue());
    }
}

迟到。

随着Java-8的出现,我们可以以非常简单/简洁的方式使用流进行数据操作。您可以使用流按值对映射条目进行排序,并创建一个LinkedHashMap,以保留插入顺序迭代。

Eg:

LinkedHashMap sortedByValueMap = map.entrySet().stream()
                .sorted(comparing(Entry<Key,Value>::getValue).thenComparing(Entry::getKey))     //first sorting by Value, then sorting by Key(entries with same value)
                .collect(LinkedHashMap::new,(map,entry) -> map.put(entry.getKey(),entry.getValue()),LinkedHashMap::putAll);

对于反向排序,请替换:

comparing(Entry<Key,Value>::getValue).thenComparing(Entry::getKey)

with

comparing(Entry<Key,Value>::getValue).thenComparing(Entry::getKey).reversed()

这是Anthony答案的变体,如果存在重复值,则该答案无效:

public static <K, V extends Comparable<V>> Map<K, V> sortMapByValues(final Map<K, V> map) {
    Comparator<K> valueComparator =  new Comparator<K>() {
        public int compare(K k1, K k2) {
            final V v1 = map.get(k1);
            final V v2 = map.get(k2);

            /* Not sure how to handle nulls ... */
            if (v1 == null) {
                return (v2 == null) ? 0 : 1;
            }

            int compare = v2.compareTo(v1);
            if (compare != 0)
            {
                return compare;
            }
            else
            {
                Integer h1 = k1.hashCode();
                Integer h2 = k2.hashCode();
                return h2.compareTo(h1);
            }
        }
    };
    Map<K, V> sortedByValues = new TreeMap<K, V>(valueComparator);
    sortedByValues.putAll(map);
    return sortedByValues;
}

注意,如何处理空值还很难说。

这种方法的一个重要优点是它实际上返回了一个Map,这与这里提供的其他解决方案不同。

对于Java 8,您可以使用streams api以一种明显不那么冗长的方式来实现:

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

要使用Java 8中的新功能实现这一点,请执行以下操作:

import static java.util.Map.Entry.comparingByValue;
import static java.util.stream.Collectors.toList;

<K, V> List<Entry<K, V>> sort(Map<K, V> map, Comparator<? super V> comparator) {
    return map.entrySet().stream().sorted(comparingByValue(comparator)).collect(toList());
}

条目使用给定的比较器按其值排序。或者,如果您的值可以相互比较,则不需要显式比较器:

<K, V extends Comparable<? super V>> List<Entry<K, V>> sort(Map<K, V> map) {
    return map.entrySet().stream().sorted(comparingByValue()).collect(toList());
}

返回的列表是调用此方法时给定映射的快照,因此两者都不会反映对另一个的后续更改。对于地图的实时可迭代视图:

<K, V extends Comparable<? super V>> Iterable<Entry<K, V>> sort(Map<K, V> map) {
    return () -> map.entrySet().stream().sorted(comparingByValue()).iterator();
}

返回的可迭代对象在每次迭代时都会创建给定映射的新快照,因此除非并发修改,否则它将始终反映映射的当前状态。