简体   繁体   English

排序 Map<key, value> 按价值观</key,>

[英]Sort a Map<Key, Value> by values

I am relatively new to Java, and often find that I need to sort a Map<Key, Value> on the values.我对 Java 比较陌生,经常发现需要对值排序一个Map<Key, Value>

Since the values are not unique, I find myself converting the keySet into an array , and sorting that array through array sort with a custom comparator that sorts on the value associated with the key.由于这些值不是唯一的,我发现自己将keySet转换为一个array ,并使用自定义比较器通过数组排序对该数组进行排序,该比较器对与键关联的值进行排序。

Is there an easier way?有没有更简单的方法?

Here's a generic-friendly version:这是一个通用的友好版本:

public class MapUtil {
    public static <K, V extends Comparable<? super V>> Map<K, V> sortByValue(Map<K, V> map) {
        List<Entry<K, V>> list = new ArrayList<>(map.entrySet());
        list.sort(Entry.comparingByValue());

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

        return result;
    }
}

Important note:重要的提示:

This code can break in multiple ways.此代码可以以多种方式中断。 If you intend to use the code provided, be sure to read the comments as well to be aware of the implications.如果您打算使用提供的代码,请务必阅读注释以了解其中的含义。 For example, values can no longer be retrieved by their key.例如,值不能再通过其键检索。 ( get always returns null .) get总是返回null 。)


It seems much easier than all of the foregoing.这似乎比上述所有内容都容易得多。 Use a TreeMap as follows:使用 TreeMap 如下:

public class Testing {
    public static void main(String[] args) {
        HashMap<String, Double> map = new HashMap<String, Double>();
        ValueComparator bvc = new ValueComparator(map);
        TreeMap<String, Double> sorted_map = new TreeMap<String, Double>(bvc);

        map.put("A", 99.5);
        map.put("B", 67.4);
        map.put("C", 67.4);
        map.put("D", 67.3);

        System.out.println("unsorted map: " + map);
        sorted_map.putAll(map);
        System.out.println("results: " + sorted_map);
    }
}

class ValueComparator implements Comparator<String> {
    Map<String, Double> base;

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

    // Note: 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: {D=67.3, A=99.5, B=67.4, C=67.4}
results: {D=67.3, B=67.4, C=67.4, A=99.5}

Java 8 offers a new answer: convert the entries into a stream, and use the comparator combinators from Map.Entry: Java 8 提供了一个新的答案:将条目转换为流,并使用 Map.Entry 中的比较器组合器:

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

This will let you consume the entries sorted in ascending order of value.这将允许您使用按值升序排序的条目。 If you want descending value, simply reverse the comparator:如果您想要递减值,只需反转比较器:

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

If the values are not comparable, you can pass an explicit comparator:如果这些值不可比较,您可以传递一个显式比较器:

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

You can then proceed to use other stream operations to consume the data.然后,您可以继续使用其他流操作来使用数据。 For example, if you want the top 10 in a new map:例如,如果您想要新地图中的前 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));

The LinkedHashMap seen above iterates entries in the order in which they were inserted.上面看到的LinkedHashMap按照插入的顺序迭代条目。

Or print to System.out :或打印到System.out

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

Three 1-line answers...三个 1 行答案...

I would use Google Collections Guava to do this - if your values are Comparable then you can use我会使用Google Collections Guava来做到这一点 - 如果你的价值观是Comparable那么你可以使用

valueComparator = Ordering.natural().onResultOf(Functions.forMap(map))

Which will create a function (object) for the map [that takes any of the keys as input, returning the respective value], and then apply natural (comparable) ordering to them [the values].这将为地图创建一个函数(对象)[将任何键作为输入,返回相应的值],然后对它们应用自然(可比较)排序[值]。

If they're not comparable, then you'll need to do something along the lines of如果它们没有可比性,那么您需要按照以下方式做一些事情

valueComparator = Ordering.from(comparator).onResultOf(Functions.forMap(map)) 

These may be applied to a TreeMap (as Ordering extends Comparator ), or a LinkedHashMap after some sorting这些可以应用于 TreeMap(因为Ordering扩展了Comparator ),或者经过一些排序后的 LinkedHashMap

NB : If you are going to use a TreeMap, remember that if a comparison == 0, then the item is already in the list (which will happen if you have multiple values that compare the same).注意:如果您要使用 TreeMap,请记住,如果比较 == 0,则该项目已经在列表中(如果您有多个比较相同的值,则会发生这种情况)。 To alleviate this, you could add your key to the comparator like so (presuming that your keys and values are Comparable ):为了缓解这种情况,您可以像这样将您的键添加到比较器(假设您的键和值是Comparable ):

valueComparator = Ordering.natural().onResultOf(Functions.forMap(map)).compound(Ordering.natural())

= Apply natural ordering to the value mapped by the key, and compound that with the natural ordering of the key =对键映射的值应用自然排序,并将其与键的自然排序复合

Note that this will still not work if your keys compare to 0, but this should be sufficient for most comparable items (as hashCode , equals and compareTo are often in sync...)请注意,如果您的键比较为 0,这仍然不起作用,但这对于大多数comparable的项目应该足够了(因为hashCodeequalscompareTo通常是同步的......)

See Ordering.onResultOf() and Functions.forMap() .请参阅Ordering.onResultOf()Functions.forMap()

Implementation执行

So now that we've got a comparator that does what we want, we need to get a result from it.所以现在我们有了一个可以做我们想要的比较器,我们需要从中得到一个结果。

map = ImmutableSortedMap.copyOf(myOriginalMap, valueComparator);

Now this will most likely work work, but:现在这很可能会起作用,但是:

  1. needs to be done given a complete finished map需要完成一张完整的地图
  2. Don't try the comparators above on a TreeMap ;不要在TreeMap上尝试上面的比较器; there's no point trying to compare an inserted key when it doesn't have a value until after the put, ie, it will break really fast当插入的键在放置之后才具有值时,尝试比较它是没有意义的,即它会非常快地中断

Point 1 is a bit of a deal-breaker for me;第 1 点对我来说有点破坏交易; google collections is incredibly lazy (which is good: you can do pretty much every operation in an instant; the real work is done when you start using the result), and this requires copying a whole map! google collections 非常懒惰(这很好:您几乎可以在瞬间完成所有操作;真正的工作在您开始使用结果时完成),这需要复制整个地图!

"Full" answer/Live sorted map by values “完整”答案/按值实时排序的地图

Don't worry though;不过不用担心; if you were obsessed enough with having a "live" map sorted in this manner, you could solve not one but both(!) of the above issues with something crazy like the following:如果您对以这种方式排序的“实时”地图非常着迷,那么您可以解决上述问题中的一个,而是解决两个(!)问题,如下所示:

Note: This has changed significantly in June 2012 - the previous code could never work: an internal HashMap is required to lookup the values without creating an infinite loop between the TreeMap.get() -> compare() and compare() -> get()注意:这在 2012 年 6 月发生了显着变化 - 以前的代码永远无法工作:需要内部 HashMap 来查找值,而不会在TreeMap.get() -> compare()compare() -> get()之间创建无限循环get()

import static org.junit.Assert.assertEquals;

import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

import com.google.common.base.Functions;
import com.google.common.collect.Ordering;

class ValueComparableMap<K extends Comparable<K>,V> extends TreeMap<K,V> {
    //A map for doing lookups on the keys for comparison so we don't get infinite loops
    private final Map<K, V> valueMap;

    ValueComparableMap(final Ordering<? super V> partialValueOrdering) {
        this(partialValueOrdering, new HashMap<K,V>());
    }

    private ValueComparableMap(Ordering<? super V> partialValueOrdering,
            HashMap<K, V> valueMap) {
        super(partialValueOrdering //Apply the value ordering
                .onResultOf(Functions.forMap(valueMap)) //On the result of getting the value for the key from the map
                .compound(Ordering.natural())); //as well as ensuring that the keys don't get clobbered
        this.valueMap = valueMap;
    }

    public V put(K k, V v) {
        if (valueMap.containsKey(k)){
            //remove the key in the sorted set before adding the key again
            remove(k);
        }
        valueMap.put(k,v); //To get "real" unsorted values for the comparator
        return super.put(k, v); //Put it in value order
    }

    public static void main(String[] args){
        TreeMap<String, Integer> map = new ValueComparableMap<String, Integer>(Ordering.natural());
        map.put("a", 5);
        map.put("b", 1);
        map.put("c", 3);
        assertEquals("b",map.firstKey());
        assertEquals("a",map.lastKey());
        map.put("d",0);
        assertEquals("d",map.firstKey());
        //ensure it's still a map (by overwriting a key, but with a new value) 
        map.put("d", 2);
        assertEquals("b", map.firstKey());
        //Ensure multiple values do not clobber keys
        map.put("e", 2);
        assertEquals(5, map.size());
        assertEquals(2, (int) map.get("e"));
        assertEquals(2, (int) map.get("d"));
    }
 }

When we put, we ensure that the hash map has the value for the comparator, and then put to the TreeSet for sorting.我们放的时候保证hash map有比较器的值,然后放到TreeSet中进行排序。 But before that we check the hash map to see that the key is not actually a duplicate.但在此之前,我们检查哈希映射以查看密钥实际上不是重复的。 Also, the comparator that we create will also include the key so that duplicate values don't delete the non-duplicate keys (due to == comparison).此外,我们创建的比较器还将包含键,以便重复值不会删除非重复键(由于 == 比较)。 These 2 items are vital for ensuring the map contract is kept;这两项对于确保保留地图合同至关重要 if you think you don't want that, then you're almost at the point of reversing the map entirely (to Map<V,K> ).如果您认为您不想要那样,那么您几乎处于完全反转地图的地步(到Map<V,K> )。

The constructor would need to be called as构造函数需要被称为

 new ValueComparableMap(Ordering.natural());
 //or
 new ValueComparableMap(Ordering.from(comparator));

From http://www.programmersheaven.com/download/49349/download.aspx来自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;
}

With Java 8, you can use the streams api to do it in a significantly less verbose way:在 Java 8 中,您可以使用流 api以一种更简洁的方式执行此操作:

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

Sorting the keys requires the Comparator to look up each value for each comparison.对键进行排序需要比较器为每次比较查找每个值。 A more scalable solution would use the entrySet directly, since then the value would be immediately available for each comparison (although I haven't backed this up by numbers).一个更具可扩展性的解决方案将直接使用 entrySet,从那时起,该值将立即可用于每次比较(尽管我没有通过数字支持这一点)。

Here's a generic version of such a thing:这是此类事物的通用版本:

public static <K, V extends Comparable<? super V>> List<K> getKeysSortedByValue(Map<K, V> map) {
    final int size = map.size();
    final List<Map.Entry<K, V>> list = new ArrayList<Map.Entry<K, V>>(size);
    list.addAll(map.entrySet());
    final ValueComparator<V> cmp = new ValueComparator<V>();
    Collections.sort(list, cmp);
    final List<K> keys = new ArrayList<K>(size);
    for (int i = 0; i < size; i++) {
        keys.set(i, list.get(i).getKey());
    }
    return keys;
}

private static final class ValueComparator<V extends Comparable<? super V>>
                                     implements Comparator<Map.Entry<?, V>> {
    public int compare(Map.Entry<?, V> o1, Map.Entry<?, V> o2) {
        return o1.getValue().compareTo(o2.getValue());
    }
}

There are ways to lessen memory rotation for the above solution.有一些方法可以减少上述解决方案的内存轮换。 The first ArrayList created could for instance be re-used as a return value;例如,创建的第一个 ArrayList 可以重新用作返回值; this would require suppression of some generics warnings, but it might be worth it for re-usable library code.这将需要抑制一些泛型警告,但对于可重用的库代码可能是值得的。 Also, the Comparator does not have to be re-allocated at every invocation.此外,Comparator 不必在每次调用时重新分配。

Here's a more efficient albeit less appealing version:这是一个更有效但不那么吸引人的版本:

public static <K, V extends Comparable<? super V>> List<K> getKeysSortedByValue2(Map<K, V> map) {
    final int size = map.size();
    final List reusedList = new ArrayList(size);
    final List<Map.Entry<K, V>> meView = reusedList;
    meView.addAll(map.entrySet());
    Collections.sort(meView, SINGLE);
    final List<K> keyView = reusedList;
    for (int i = 0; i < size; i++) {
        keyView.set(i, meView.get(i).getKey());
    }
    return keyView;
}

private static final Comparator SINGLE = new ValueComparator();

Finally, if you need to continously access the sorted information (rather than just sorting it once in a while), you can use an additional multi map.最后,如果您需要持续访问排序后的信息(而不是偶尔排序一次),您可以使用额外的多图。 Let me know if you need more details...如果您需要更多详细信息,请告诉我...

The commons-collections library contains a solution called TreeBidiMap . commons-collections 库包含一个名为TreeBidiMap的解决方案。 Or, you could have a look at the Google Collections API.或者,您可以查看 Google Collections API。 It has TreeMultimap which you could use.它有你可以使用的TreeMultimap

And if you don't want to use these framework... they come with source code.如果你不想使用这些框架......它们带有源代码。

I've looked at the given answers, but a lot of them are more complicated than needed or remove map elements when several keys have same value.我已经查看了给定的答案,但是其中很多都比需要的更复杂,或者当多个键具有相同的值时删除地图元素。

Here is a solution that I think fits better:这是我认为更合适的解决方案:

public static <K, V extends Comparable<V>> Map<K, V> sortByValues(final Map<K, V> map) {
    Comparator<K> valueComparator =  new Comparator<K>() {
        public int compare(K k1, K k2) {
            int compare = map.get(k2).compareTo(map.get(k1));
            if (compare == 0) return 1;
            else return compare;
        }
    };
    Map<K, V> sortedByValues = new TreeMap<K, V>(valueComparator);
    sortedByValues.putAll(map);
    return sortedByValues;
}

Note that the map is sorted from the highest value to the lowest.请注意,地图是从最高值到最低值排序的。

Given Map给定地图

   Map<String, Integer> wordCounts = new HashMap<>();
    wordCounts.put("USA", 100);
    wordCounts.put("jobs", 200);
    wordCounts.put("software", 50);
    wordCounts.put("technology", 70);
    wordCounts.put("opportunity", 200);

Sort the map based on the value in ascending order根据值升序对地图进行排序

Map<String,Integer>  sortedMap =  wordCounts.entrySet().
                                                stream().
                                                sorted(Map.Entry.comparingByValue()).
        collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
    System.out.println(sortedMap);
    

Sort the map based on value in descending order根据值按降序对地图进行排序

Map<String,Integer>  sortedMapReverseOrder =  wordCounts.entrySet().
            stream().
            sorted(Map.Entry.comparingByValue(Comparator.reverseOrder())).
            collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
    System.out.println(sortedMapReverseOrder);

Output:输出:

{software=50, technology=70, USA=100, jobs=200, opportunity=200} {软件=50,技术=70,美国=100,工作=200,机会=200}

{jobs=200, opportunity=200, USA=100, technology=70, software=50} {工作=200,机会=200,美国=100,技术=70,软件=50}

To accomplish this with the new features in Java 8:要使用 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());
}

The entries are ordered by their values using the given comparator.条目使用给定的比较器按它们的值排序。 Alternatively, if your values are mutually comparable, no explicit comparator is needed:或者,如果您的值可以相互比较,则不需要显式比较器:

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

The returned list is a snapshot of the given map at the time this method is called, so neither will reflect subsequent changes to the other.返回的列表是调用此方法时给定地图的快照,因此两者都不会反映对另一个的后续更改。 For a live iterable view of the map:对于地图的实时可迭代视图:

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

The returned iterable creates a fresh snapshot of the given map each time it's iterated, so barring concurrent modification, it will always reflect the current state of the map.返回的可迭代对象在每次迭代时都会创建给定映射的新快照,因此除非并发修改,否则它将始终反映映射的当前状态。

Create customized comparator and use it while creating new TreeMap object.创建自定义比较器并在创建新 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));

    }
}

Use the below code in your main func在您的主要功能中使用以下代码

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

Output:输出:

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

While I agree that the constant need to sort a map is probably a smell, I think the following code is the easiest way to do it without using a different data structure.虽然我同意对地图进行排序的持续需求可能是一种气味,但我认为以下代码是不使用不同数据结构的最简单方法。

public class MapUtilities {

public static <K, V extends Comparable<V>> List<Entry<K, V>> sortByValue(Map<K, V> map) {
    List<Entry<K, V>> entries = new ArrayList<Entry<K, V>>(map.entrySet());
    Collections.sort(entries, new ByValue<K, V>());
    return entries;
}

private static class ByValue<K, V extends Comparable<V>> implements Comparator<Entry<K, V>> {
    public int compare(Entry<K, V> o1, Entry<K, V> o2) {
        return o1.getValue().compareTo(o2.getValue());
    }
}

} }

And here is an embarrassingly incomplete unit test:这是一个令人尴尬的不完整的单元测试:

public class MapUtilitiesTest extends TestCase {
public void testSorting() {
    HashMap<String, Integer> map = new HashMap<String, Integer>();
    map.put("One", 1);
    map.put("Two", 2);
    map.put("Three", 3);

    List<Map.Entry<String, Integer>> sorted = MapUtilities.sortByValue(map);
    assertEquals("First", "One", sorted.get(0).getKey());
    assertEquals("Second", "Two", sorted.get(1).getKey());
    assertEquals("Third", "Three", sorted.get(2).getKey());
}

} }

The result is a sorted list of Map.Entry objects, from which you can obtain the keys and values.结果是 Map.Entry 对象的排序列表,您可以从中获取键和值。

Use a generic comparator such as:使用通用比较器,例如:

final class MapValueComparator<K,V extends Comparable<V>> implements Comparator<K> {
    private final Map<K,V> map;
    
    private MapValueComparator() {
        super();
    }
    
    public MapValueComparator(Map<K,V> map) {
        this();
        this.map = map;
    }
        
    public int compare(K o1, K o2) {
        return map.get(o1).compareTo(map.get(o2));
    }
}

The answer voted for the most does not work when you have 2 items that equals.当您有 2 个相等的项目时,投票最多的答案不起作用。 the TreeMap leaves equal values out. TreeMap 会留下相等的值。

the exmaple: unsorted map示例:未排序的地图

key/value: D/67.3
key/value: A/99.5
key/value: B/67.4
key/value: C/67.5
key/value: E/99.5

results结果

key/value: A/99.5
key/value: C/67.5
key/value: B/67.4
key/value: D/67.3

So leaves out E!!所以省略E!

For me it worked fine to adjust the comparator, if it equals do not return 0 but -1.对我来说,调整比较器效果很好,如果它等于不返回 0 而是 -1。

in the example:在示例中:

class ValueComparator implements Comparator {类 ValueComparator 实现 Comparator {

Map base;地图基地; public ValueComparator(Map base) { this.base = base; public ValueComparator(Map base) { this.base = base; } }

public int compare(Object a, Object b) {公共 int 比较(对象 a,对象 b){

 if((Double)base.get(a) < (Double)base.get(b)) { return 1; } else if((Double)base.get(a) == (Double)base.get(b)) { return -1; } else { return -1; }

} } } }

now it returns:现在它返回:

unsorted map:未排序的地图:

key/value: D/67.3
key/value: A/99.5
key/value: B/67.4
key/value: C/67.5
key/value: E/99.5

results:结果:

key/value: A/99.5
key/value: E/99.5
key/value: C/67.5
key/value: B/67.4
key/value: D/67.3

as a response to Aliens (2011 nov. 22): I Am using this solution for a map of Integer Id's and names, but the idea is the same, so might be the code above is not correct (I will write it in a test and give you the correct code), this is the code for a Map sorting, based on the solution above:作为对 Aliens(2011 年 11 月 22 日)的回应:我正在将此解决方案用于整数 ID 和名称的映射,但想法是相同的,所以可能是上面的代码不正确(我将在测试中编写它并给你正确的代码),这是地图排序的代码,基于上面的解决方案:

package nl.iamit.util;

import java.util.Comparator;
import java.util.Map;

public class Comparators {


    public static class MapIntegerStringComparator implements Comparator {

        Map<Integer, String> base;

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

        public int compare(Object a, Object b) {

            int compare = ((String) base.get(a))
                    .compareTo((String) base.get(b));
            if (compare == 0) {
                return -1;
            }
            return compare;
        }
    }


}

and this is the test class (I just tested it, and this works for the Integer, String Map:这是测试类(我刚刚测试过,这适用于整数、字符串映射:

package test.nl.iamit.util;

import java.util.HashMap;
import java.util.TreeMap;
import nl.iamit.util.Comparators;
import org.junit.Test;
import static org.junit.Assert.assertArrayEquals;

public class TestComparators {


    @Test
    public void testMapIntegerStringComparator(){
        HashMap<Integer, String> unSoretedMap = new HashMap<Integer, String>();
        Comparators.MapIntegerStringComparator bvc = new Comparators.MapIntegerStringComparator(
                unSoretedMap);
        TreeMap<Integer, String> sorted_map = new TreeMap<Integer, String>(bvc);
        //the testdata:
        unSoretedMap.put(new Integer(1), "E");
        unSoretedMap.put(new Integer(2), "A");
        unSoretedMap.put(new Integer(3), "E");
        unSoretedMap.put(new Integer(4), "B");
        unSoretedMap.put(new Integer(5), "F");

        sorted_map.putAll(unSoretedMap);

        Object[] targetKeys={new Integer(2),new Integer(4),new Integer(3),new Integer(1),new Integer(5) };
        Object[] currecntKeys=sorted_map.keySet().toArray();

        assertArrayEquals(targetKeys,currecntKeys);
    }
}

here is the code for the Comparator of a Map:这是地图比较器的代码:

public static class MapStringDoubleComparator implements Comparator {

    Map<String, Double> base;

    public MapStringDoubleComparator(Map<String, Double> base) {
        this.base = base;
    }

    //note if you want decending in stead of ascending, turn around 1 and -1
    public int compare(Object a, Object b) {
        if ((Double) base.get(a) == (Double) base.get(b)) {
            return 0;
        } else if((Double) base.get(a) < (Double) base.get(b)) {
            return -1;
        }else{
            return 1;
        }
    }
}

and this is the testcase for this:这是测试用例:

@Test
public void testMapStringDoubleComparator(){
    HashMap<String, Double> unSoretedMap = new HashMap<String, Double>();
    Comparators.MapStringDoubleComparator bvc = new Comparators.MapStringDoubleComparator(
            unSoretedMap);
    TreeMap<String, Double> sorted_map = new TreeMap<String, Double>(bvc);
    //the testdata:
    unSoretedMap.put("D",new Double(67.3));
    unSoretedMap.put("A",new Double(99.5));
    unSoretedMap.put("B",new Double(67.4));
    unSoretedMap.put("C",new Double(67.5));
    unSoretedMap.put("E",new Double(99.5));

    sorted_map.putAll(unSoretedMap);

    Object[] targetKeys={"D","B","C","E","A"};
    Object[] currecntKeys=sorted_map.keySet().toArray();

    assertArrayEquals(targetKeys,currecntKeys);
}

of cource you can make this a lot more generic, but I just needed it for 1 case (the Map)当然你可以让它更通用,但我只需要它来处理 1 个案例(地图)

Instead of using Collections.sort as some do I'd suggest using Arrays.sort .我建议不要像某些人那样使用Collections.sort ,而是使用Arrays.sort Actually what Collections.sort does is something like this:实际上Collections.sort所做的是这样的:

public static <T extends Comparable<? super T>> void sort(List<T> list) {
    Object[] a = list.toArray();
    Arrays.sort(a);
    ListIterator<T> i = list.listIterator();
    for (int j=0; j<a.length; j++) {
        i.next();
        i.set((T)a[j]);
    }
}

It just calls toArray on the list and then uses Arrays.sort .它只是调用列表上的toArray ,然后使用Arrays.sort This way all the map entries will be copied three times: once from the map to the temporary list (be it a LinkedList or ArrayList), then to the temporary array and finally to the new map.这样所有的地图条目将被复制三次:一次从地图复制到临时列表(无论是 LinkedList 还是 ArrayList),然后复制到临时数组,最后复制到新地图。

My solution ommits this one step as it does not create unnecessary LinkedList.我的解决方案省略了这一步,因为它不会创建不必要的 LinkedList。 Here is the code, generic-friendly and performance-optimal:这是代码,通用友好且性能最佳:

public static <K, V extends Comparable<? super V>> Map<K, V> sortByValue(Map<K, V> map) 
{
    @SuppressWarnings("unchecked")
    Map.Entry<K,V>[] array = map.entrySet().toArray(new Map.Entry[map.size()]);

    Arrays.sort(array, new Comparator<Map.Entry<K, V>>() 
    {
        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<K, V>();
    for (Map.Entry<K, V> entry : array)
        result.put(entry.getKey(), entry.getValue());

    return result;
}

Best Approach最佳方法

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry; 

public class OrderByValue {

  public static void main(String a[]){
    Map<String, Integer> map = new HashMap<String, Integer>();
    map.put("java", 20);
    map.put("C++", 45);
    map.put("Unix", 67);
    map.put("MAC", 26);
    map.put("Why this kolavari", 93);
    Set<Entry<String, Integer>> set = map.entrySet();
    List<Entry<String, Integer>> list = new ArrayList<Entry<String, Integer>>(set);
    Collections.sort( list, new Comparator<Map.Entry<String, Integer>>()
    {
        public int compare( Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2 )
        {
            return (o1.getValue()).compareTo( o2.getValue() );//Ascending order
            //return (o2.getValue()).compareTo( o1.getValue() );//Descending order
        }
    } );
    for(Map.Entry<String, Integer> entry:list){
        System.out.println(entry.getKey()+" ==== "+entry.getValue());
    }
  }}

Output输出

java ==== 20

MAC ==== 26

C++ ==== 45

Unix ==== 67

Why this kolavari ==== 93

This is a variation of Anthony's answer, which doesn't work if there are duplicate values:这是 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;
}

Note that it's rather up in the air how to handle nulls.请注意,如何处理空值尚无定论。

One important advantage of this approach is that it actually returns a Map, unlike some of the other solutions offered here.这种方法的一个重要优点是它实际上返回了一个 Map,这与这里提供的其他一些解决方案不同。

Late Entry.迟到。

With the advent of Java-8, we can use streams for data manipulation in a very easy/succinct way.随着 Java-8 的出现,我们可以以非常简单/简洁的方式使用流进行数据操作。 You can use streams to sort the map entries by value and create a LinkedHashMap which preserves insertion-order iteration.您可以使用流按值对映射条目进行排序,并创建一个保留插入顺序迭代的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);

For reverse ordering, replace:对于反向排序,请替换:

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

with

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

Major problem.主要问题。 If you use the first answer (Google takes you here), change the comparator to add an equal clause, otherwise you cannot get values from the sorted_map by keys:如果您使用第一个答案(Google 将您带到此处),请更改比较器以添加相等子句,否则您无法通过键从 sorted_map 获取值:

public int compare(String a, String b) {
        if (base.get(a) > base.get(b)) {
            return 1;
        } else if (base.get(a) < base.get(b)){
            return -1;
        } 

        return 0;
        // returning 0 would merge keys
    }

There are a lot of answers for this question already, but none provided me what I was looking for, a map implementation that returns keys and entries sorted by the associated value, and maintains this property as keys and values are modified in the map.这个问题已经有很多答案了,但是没有一个能提供我正在寻找的东西,一个映射实现,它返回按关联值排序的键和条目,并在映射中修改键和值时维护这个属性。 Two other questions ask for this specifically.另外两个问题专门针对这个问题。

I cooked up a generic friendly example that solves this use case.我制作了一个通用的友好示例来解决这个用例。 This implementation does not honor all of the contracts of the Map interface, such as reflecting value changes and removals in the sets return from keySet() and entrySet() in the original object.此实现不遵守 Map 接口的所有约定,例如反映从原始对象中的 keySet() 和 entrySet() 返回的集合中的值更改和删除。 I felt such a solution would be too large to include in a Stack Overflow answer.我觉得这样的解决方案太大而无法包含在 Stack Overflow 的答案中。 If I manage to create a more complete implementation, perhaps I will post it to Github and then to it link in an updated version of this answer.如果我设法创建一个更完整的实现,也许我会将它发布到 Github,然后在这个答案的更新版本中链接到它。

import java.util.*;

/**
 * A map where {@link #keySet()} and {@link #entrySet()} return sets ordered
 * by associated values based on the the comparator provided at construction
 * time. The order of two or more keys with identical values is not defined.
 * <p>
 * Several contracts of the Map interface are not satisfied by this minimal
 * implementation.
 */
public class ValueSortedMap<K, V> extends HashMap<K, V> {
    protected Map<V, Collection<K>> valueToKeysMap;

    // uses natural order of value object, if any
    public ValueSortedMap() {
        this((Comparator<? super V>) null);
    }

    public ValueSortedMap(Comparator<? super V> valueComparator) {
        this.valueToKeysMap = new TreeMap<V, Collection<K>>(valueComparator);
    }

    public boolean containsValue(Object o) {
        return valueToKeysMap.containsKey(o);
    }

    public V put(K k, V v) {
        V oldV = null;
        if (containsKey(k)) {
            oldV = get(k);
            valueToKeysMap.get(oldV).remove(k);
        }
        super.put(k, v);
        if (!valueToKeysMap.containsKey(v)) {
            Collection<K> keys = new ArrayList<K>();
            keys.add(k);
            valueToKeysMap.put(v, keys);
        } else {
            valueToKeysMap.get(v).add(k);
        }
        return oldV;
    }

    public void putAll(Map<? extends K, ? extends V> m) {
        for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
            put(e.getKey(), e.getValue());
    }

    public V remove(Object k) {
        V oldV = null;
        if (containsKey(k)) {
            oldV = get(k);
            super.remove(k);
            valueToKeysMap.get(oldV).remove(k);
        }
        return oldV;
    }

    public void clear() {
        super.clear();
        valueToKeysMap.clear();
    }

    public Set<K> keySet() {
        LinkedHashSet<K> ret = new LinkedHashSet<K>(size());
        for (V v : valueToKeysMap.keySet()) {
            Collection<K> keys = valueToKeysMap.get(v);
            ret.addAll(keys);
        }
        return ret;
    }

    public Set<Map.Entry<K, V>> entrySet() {
        LinkedHashSet<Map.Entry<K, V>> ret = new LinkedHashSet<Map.Entry<K, V>>(size());
        for (Collection<K> keys : valueToKeysMap.values()) {
            for (final K k : keys) {
                final V v = get(k);
                ret.add(new Map.Entry<K,V>() {
                    public K getKey() {
                        return k;
                    }

                    public V getValue() {
                        return v;
                    }

                    public V setValue(V v) {
                        throw new UnsupportedOperationException();
                    }
                });
            }
        }
        return ret;
    }
}

Simple way to sort any map in Java 8 and above在 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());
}

if you are using Java 7 and below如果您使用的是 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());
}

Depending on the context, using java.util.LinkedHashMap<T> which rememebers the order in which items are placed into the map.根据上下文,使用java.util.LinkedHashMap<T>记住项目放入地图的顺序。 Otherwise, if you need to sort values based on their natural ordering, I would recommend maintaining a separate List which can be sorted via Collections.sort() .否则,如果您需要根据值的自然顺序对值进行排序,我建议您维护一个单独的 List ,可以通过Collections.sort()对其进行排序。

This is just too complicated.这太复杂了。 Maps were not supposed to do such job as sorting them by Value.地图不应该做按价值对它们进行排序这样的工作。 The easiest way is to create your own Class so it fits your requirement.最简单的方法是创建您自己的类,使其符合您的要求。

In example lower you are supposed to add TreeMap a comparator at place where * is.在较低的示例中,您应该在 * 所在的位置添加 TreeMap 比较器。 But by java API it gives comparator only keys, not values.但是通过 java API,它只给比较器提供键,而不是值。 All of examples stated here is based on 2 Maps.此处所述的所有示例均基于 2 个地图。 One Hash and one new Tree.一个哈希和一个新树。 Which is odd.这很奇怪。

The example:这个例子:

Map<Driver driver, Float time> map = new TreeMap<Driver driver, Float time>(*);

So change the map into a set this way:因此,以这种方式将地图更改为一组:

ResultComparator rc = new ResultComparator();
Set<Results> set = new TreeSet<Results>(rc);

You will create class Results ,您将创建类Results

public class Results {
    private Driver driver;
    private Float time;

    public Results(Driver driver, Float time) {
        this.driver = driver;
        this.time = time;
    }

    public Float getTime() {
        return time;
    }

    public void setTime(Float time) {
        this.time = time;
    }

    public Driver getDriver() {
        return driver;
    }

    public void setDriver (Driver driver) {
        this.driver = driver;
    }
}

and the Comparator class:和比较器类:

public class ResultsComparator implements Comparator<Results> {
    public int compare(Results t, Results t1) {
        if (t.getTime() < t1.getTime()) {
            return 1;
        } else if (t.getTime() == t1.getTime()) {
            return 0;
        } else {
            return -1;
        }
    }
}

This way you can easily add more dependencies.这样您就可以轻松添加更多依赖项。

And as the last point I'll add simple iterator:最后一点,我将添加简单的迭代器:

Iterator it = set.iterator();
while (it.hasNext()) {
    Results r = (Results)it.next();
    System.out.println( r.getDriver().toString
        //or whatever that is related to Driver class -getName() getSurname()
        + " "
        + r.getTime()
        );
}

Afaik the most cleaner way is utilizing collections to sort map on value: Afaik 最干净的方法是利用集合对值进行排序:

Map<String, Long> map = new HashMap<String, Long>();
// populate with data to sort on Value
// use datastructure designed for sorting

Queue queue = new PriorityQueue( map.size(), new MapComparable() );
queue.addAll( map.entrySet() );

// get a sorted map
LinkedHashMap<String, Long> linkedMap = new LinkedHashMap<String, Long>();

for (Map.Entry<String, Long> entry; (entry = queue.poll())!=null;) {
    linkedMap.put(entry.getKey(), entry.getValue());
}

public static class MapComparable implements Comparator<Map.Entry<String, Long>>{

  public int compare(Entry<String, Long> e1, Entry<String, Long> e2) {
    return e1.getValue().compareTo(e2.getValue());
  }
}

Since TreeMap<> does not work for values that can be equal, I used this:由于TreeMap<> 不适用于可以相等的值,我使用了这个:

private <K, V extends Comparable<? super V>> List<Entry<K, V>> sort(Map<K, V> map)     {
    List<Map.Entry<K, V>> list = new LinkedList<Map.Entry<K, V>>(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());
        }
    });

    return list;
}

You might want to put list in a LinkedHashMap , but if you're only going to iterate over it right away, that's superfluous...您可能想将list放入LinkedHashMap ,但如果您只想立即对其进行迭代,那是多余的......

Here is an OO solution (ie, doesn't use static methods):这是一个面向对象的解决方案(即,不使用static方法):

import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

public class SortableValueMap<K, V extends Comparable<V>>
  extends LinkedHashMap<K, V> {
  public SortableValueMap() { }

  public SortableValueMap( Map<K, V> map ) {
    super( map );
  }

  public void sortByValue() {
    List<Map.Entry<K, V>> list = new LinkedList<Map.Entry<K, V>>( entrySet() );

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

    clear();

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

  private static void print( String text, Map<String, Double> map ) {
    System.out.println( text );

    for( String key : map.keySet() ) {
      System.out.println( "key/value: " + key + "/" + map.get( key ) );
    }
  }

  public static void main( String[] args ) {
    SortableValueMap<String, Double> map =
      new SortableValueMap<String, Double>();

    map.put( "A", 67.5 );
    map.put( "B", 99.5 );
    map.put( "C", 82.4 );
    map.put( "D", 42.0 );

    print( "Unsorted map", map );
    map.sortByValue();
    print( "Sorted map", map );
  }
}

Hereby donated to the public domain.特此捐赠给公共领域。

This could be achieved very easily with java 8使用 java 8 可以很容易地实现这一点

public static LinkedHashMap<Integer, String> sortByValue(HashMap<Integer, String> map) {

        List<Map.Entry<Integer, String>> list = new ArrayList<>(map.entrySet());
        list.sort(Map.Entry.comparingByValue());
        LinkedHashMap<Integer, String> sortedMap = new LinkedHashMap<>();
        list.forEach(e -> sortedMap.put(e.getKey(), e.getValue()));
        return sortedMap;
    }

Some simple changes in order to have a sorted map with pairs that have duplicate values.一些简单的更改,以便有一个带有重复值对的排序映射。 In the compare method (class ValueComparator) when values are equal do not return 0 but return the result of comparing the 2 keys.在比较方法(ValueComparator 类)中,当值相等时,不返回 0,而是返回比较 2 个键的结果。 Keys are distinct in a map so you succeed to keep duplicate values (which are sorted by keys by the way).映射中的键是不同的,因此您可以成功保留重复值(顺便说一下,这些值是按键排序的)。 So the above example could be modified like this:所以上面的例子可以这样修改:

    public int compare(Object a, Object b) {

        if((Double)base.get(a) < (Double)base.get(b)) {
          return 1;
        } else if((Double)base.get(a) == (Double)base.get(b)) {
          return ((String)a).compareTo((String)b);
        } else {
          return -1;
        }
      }
    }

Based on @devinmoore code, a map sorting methods using generics and supporting both ascending and descending ordering.基于@devinmoore 代码,一种使用泛型并支持升序和降序的地图排序方法。

/**
 * Sort a map by it's keys in ascending order. 
 *  
 * @return new instance of {@link LinkedHashMap} contained sorted entries of supplied map.
 * @author Maxim Veksler
 */
public static <K, V> LinkedHashMap<K, V> sortMapByKey(final Map<K, V> map) {
    return sortMapByKey(map, SortingOrder.ASCENDING);
}

/**
 * Sort a map by it's values in ascending order.
 *  
 * @return new instance of {@link LinkedHashMap} contained sorted entries of supplied map.
 * @author Maxim Veksler
 */
public static <K, V> LinkedHashMap<K, V> sortMapByValue(final Map<K, V> map) {
    return sortMapByValue(map, SortingOrder.ASCENDING);
}

/**
 * Sort a map by it's keys.
 *  
 * @param sortingOrder {@link SortingOrder} enum specifying requested sorting order. 
 * @return new instance of {@link LinkedHashMap} contained sorted entries of supplied map.
 * @author Maxim Veksler
 */
public static <K, V> LinkedHashMap<K, V> sortMapByKey(final Map<K, V> map, final SortingOrder sortingOrder) {
    Comparator<Map.Entry<K, V>> comparator = new Comparator<Entry<K,V>>() {
        public int compare(Entry<K, V> o1, Entry<K, V> o2) {
            return comparableCompare(o1.getKey(), o2.getKey(), sortingOrder);
        }
    };

    return sortMap(map, comparator);
}

/**
 * Sort a map by it's values.
 *  
 * @param sortingOrder {@link SortingOrder} enum specifying requested sorting order. 
 * @return new instance of {@link LinkedHashMap} contained sorted entries of supplied map.
 * @author Maxim Veksler
 */
public static <K, V> LinkedHashMap<K, V> sortMapByValue(final Map<K, V> map, final SortingOrder sortingOrder) {
    Comparator<Map.Entry<K, V>> comparator = new Comparator<Entry<K,V>>() {
        public int compare(Entry<K, V> o1, Entry<K, V> o2) {
            return comparableCompare(o1.getValue(), o2.getValue(), sortingOrder);
        }
    };

    return sortMap(map, comparator);
}

@SuppressWarnings("unchecked")
private static <T> int comparableCompare(T o1, T o2, SortingOrder sortingOrder) {
    int compare = ((Comparable<T>)o1).compareTo(o2);

    switch (sortingOrder) {
    case ASCENDING:
        return compare;
    case DESCENDING:
        return (-1) * compare;
    }

    return 0;
}

/**
 * Sort a map by supplied comparator logic.
 *  
 * @return new instance of {@link LinkedHashMap} contained sorted entries of supplied map.
 * @author Maxim Veksler
 */
public static <K, V> LinkedHashMap<K, V> sortMap(final Map<K, V> map, final Comparator<Map.Entry<K, V>> comparator) {
    // Convert the map into a list of key,value pairs.
    List<Map.Entry<K, V>> mapEntries = new LinkedList<Map.Entry<K, V>>(map.entrySet());

    // Sort the converted list according to supplied comparator.
    Collections.sort(mapEntries, comparator);

    // Build a new ordered map, containing the same entries as the old map.  
    LinkedHashMap<K, V> result = new LinkedHashMap<K, V>(map.size() + (map.size() / 20));
    for(Map.Entry<K, V> entry : mapEntries) {
        // We iterate on the mapEntries list which is sorted by the comparator putting new entries into 
        // the targeted result which is a sorted map. 
        result.put(entry.getKey(), entry.getValue());
    }

    return result;
}

/**
 * Sorting order enum, specifying request result sort behavior.
 * @author Maxim Veksler
 *
 */
public static enum SortingOrder {
    /**
     * Resulting sort will be from smaller to biggest.
     */
    ASCENDING,
    /**
     * Resulting sort will be from biggest to smallest.
     */
    DESCENDING
}

For sure the solution of Stephen is really great, but for those who can't use Guava:当然斯蒂芬的解决方案真的很棒,但是对于那些不能使用番石榴的人:

Here's my solution for sorting by value a map.这是我按值排序地图的解决方案。 This solution handle the case where there are twice the same value etc...该解决方案处理存在两倍相同值等的情况......

// If you want to sort a map by value, and if there can be twice the same value:

// here is your original map
Map<String,Integer> mapToSortByValue = new HashMap<String, Integer>();
mapToSortByValue.put("A", 3);
mapToSortByValue.put("B", 1);
mapToSortByValue.put("C", 3);
mapToSortByValue.put("D", 5);
mapToSortByValue.put("E", -1);
mapToSortByValue.put("F", 1000);
mapToSortByValue.put("G", 79);
mapToSortByValue.put("H", 15);

// Sort all the map entries by value
Set<Map.Entry<String,Integer>> set = new TreeSet<Map.Entry<String,Integer>>(
        new Comparator<Map.Entry<String,Integer>>(){
            @Override
            public int compare(Map.Entry<String,Integer> obj1, Map.Entry<String,Integer> obj2) {
                Integer val1 = obj1.getValue();
                Integer val2 = obj2.getValue();
                // DUPLICATE VALUE CASE
                // If the values are equals, we can't return 0 because the 2 entries would be considered
                // as equals and one of them would be deleted (because we use a set, no duplicate, remember!)
                int compareValues = val1.compareTo(val2);
                if ( compareValues == 0 ) {
                    String key1 = obj1.getKey();
                    String key2 = obj2.getKey();
                    int compareKeys = key1.compareTo(key2);
                    if ( compareKeys == 0 ) {
                        // what you return here will tell us if you keep REAL KEY-VALUE duplicates in your set
                        // if you want to, do whatever you want but do not return 0 (but don't break the comparator contract!)
                        return 0;
                    }
                    return compareKeys;
                }
                return compareValues;
            }
        }
);
set.addAll(mapToSortByValue.entrySet());


// OK NOW OUR SET IS SORTED COOL!!!!

// And there's nothing more to do: the entries are sorted by value!
for ( Map.Entry<String,Integer> entry : set ) {
    System.out.println("Set entries: " + entry.getKey() + " -> " + entry.getValue());
}




// But if you add them to an hashmap
Map<String,Integer> myMap = new HashMap<String,Integer>();
// When iterating over the set the order is still good in the println...
for ( Map.Entry<String,Integer> entry : set ) {
    System.out.println("Added to result map entries: " + entry.getKey() + " " + entry.getValue());
    myMap.put(entry.getKey(), entry.getValue());
}

// But once they are in the hashmap, the order is not kept!
for ( Integer value : myMap.values() ) {
    System.out.println("Result map values: " + value);
}
// Also this way doesn't work:
// Logic because the entryset is a hashset for hashmaps and not a treeset
// (and even if it was a treeset, it would be on the keys only)
for ( Map.Entry<String,Integer> entry : myMap.entrySet() ) {
    System.out.println("Result map entries: " + entry.getKey() + " -> " + entry.getValue());
}


// CONCLUSION:
// If you want to iterate on a map ordered by value, you need to remember:
// 1) Maps are only sorted by keys, so you can't sort them directly by value
// 2) So you simply CAN'T return a map to a sortMapByValue function
// 3) You can't reverse the keys and the values because you have duplicate values
//    This also means you can't neither use Guava/Commons bidirectionnal treemaps or stuff like that

// SOLUTIONS
// So you can:
// 1) only sort the values which is easy, but you loose the key/value link (since you have duplicate values)
// 2) sort the map entries, but don't forget to handle the duplicate value case (like i did)
// 3) if you really need to return a map, use a LinkedHashMap which keep the insertion order

The exec: http://www.ideone.com/dq3Lu执行官: http ://www.ideone.com/dq3Lu

The output:输出:

Set entries: E -> -1
Set entries: B -> 1
Set entries: A -> 3
Set entries: C -> 3
Set entries: D -> 5
Set entries: H -> 15
Set entries: G -> 79
Set entries: F -> 1000
Added to result map entries: E -1
Added to result map entries: B 1
Added to result map entries: A 3
Added to result map entries: C 3
Added to result map entries: D 5
Added to result map entries: H 15
Added to result map entries: G 79
Added to result map entries: F 1000
Result map values: 5
Result map values: -1
Result map values: 1000
Result map values: 79
Result map values: 3
Result map values: 1
Result map values: 3
Result map values: 15
Result map entries: D -> 5
Result map entries: E -> -1
Result map entries: F -> 1000
Result map entries: G -> 79
Result map entries: A -> 3
Result map entries: B -> 1
Result map entries: C -> 3
Result map entries: H -> 15

Hope it will help some folks希望它会帮助一些人

You can try Guava's multimaps:你可以试试 Guava 的多图:

TreeMap<Integer, Collection<String>> sortedMap = new TreeMap<>(
        Multimaps.invertFrom(Multimaps.forMap(originalMap), 
        ArrayListMultimap.<Integer, String>create()).asMap());

As a result you get a map from original values to collections of keys that correspond to them.结果,您获得了从原始值到对应于它们的键集合的映射。 This approach can be used even if there are multiple keys for the same value.即使同一值有多个键,也可以使用此方法。

I've merged the solutions of user157196 and Carter Page:我已经合并了 user157196 和 Carter Page 的解决方案:

class MapUtil {

    public static <K, V extends Comparable<? super V>> Map<K, V> sortByValue( Map<K, V> map ){
        ValueComparator<K,V> bvc =  new ValueComparator<K,V>(map);
        TreeMap<K,V> sorted_map = new TreeMap<K,V>(bvc);
        sorted_map.putAll(map);
        return sorted_map;
    }

}

class ValueComparator<K, V extends Comparable<? super V>> implements Comparator<K> {

    Map<K, V> base;
    public ValueComparator(Map<K, V> base) {
        this.base = base;
    }

    public int compare(K a, K b) {
        int result = (base.get(a).compareTo(base.get(b)));
        if (result == 0) result=1;
        // returning 0 would merge keys
        return result;
    }
}

Here is the code by Java 8 with AbacusUtil这是 Java 8 和AbacusUtil的代码

Map<String, Integer> map = N.asMap("a", 2, "b", 3, "c", 1, "d", 2);
Map<String, Integer> sortedMap = Stream.of(map.entrySet()).sorted(Map.Entry.comparingByValue()).toMap(e -> e.getKey(), e -> e.getValue(),
    LinkedHashMap::new);
N.println(sortedMap);
// output: {c=1, a=2, d=2, b=3}

Declaration: I'm the developer of AbacusUtil.声明:我是AbacusUtil的开发者。

Sort any Hashmap the easiest way in Java.在 Java 中以最简单的方式对任何 Hashmap 进行排序。 We need not store it in treemaps, list etc.我们不需要将它存储在树形图、列表等中。

Here, I would be using Java Streams:在这里,我将使用 Java Streams:

Lets sort this map by its value (Ascending order)让我们按它的值对这张地图进行排序(升序)

Map<String, Integer> mp= new HashMap<>();
mp.put("zebra", 1);
mp.put("blossom", 2);
mp.put("gemini", 3);
mp.put("opera", 7);
mp.put("adelaide", 10);

Map<String, Integer> resultMap= mp.entrySet().stream().sorted(Map.Entry.<String, Integer>comparingByValue()).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,(e1, e2) -> e1, LinkedHashMap::new));

You can now printed the sorted resultMap in multiple ways like using advanced for loops or iterators.您现在可以通过多种方式打印排序的 resultMap,例如使用高级 for 循环或迭代器。

The above map can also be sorted in descending order of the value上图也可以按值降序排列

 Map<String, Integer> resultMap= mp.entrySet().stream().sorted(Map.Entry.<String, Integer>comparingByValue().reversed()).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,(e1, e2) -> e1, LinkedHashMap::new));

Lets now take another scenario where we store "User" in the map and sort it based on "name" of the "User" in ascending order (lexicographically):现在让我们看另一个场景,我们将“用户”存储在地图中,并根据“用户”的“名称”按升序(按字典顺序)对其进行排序:

User u1= new User("hi", 135);
User u2= new User("bismuth", 900);
User u3= new User("alloy", 675);
User u4= new User("jupiter", 342);
User u5= new User("lily", 941);

Map<String, User> map2= new HashMap<>();
map2.put("zebra", u3);
map2.put("blossom", u5);
map2.put("gemini", u1);
map2.put("opera", u2);
map2.put("adelaide", u4);


Map<String, User>  resultMap= 
          map2.entrySet().stream().sorted(Map.Entry.<String, User>comparingByValue( (User o1, User o2)-> o1.getName().compareTo(o2.getName()))).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,(e1, e2) -> e2, LinkedHashMap::new));



class User
 {
    String name;
    int id;
        

public User(String name, int id) {
    super();
    this.name = name;
    this.id = id;
}
public String getName() {
    return name;
}
public void setName(String name) {
    this.name = name;
}
public int getId() {
    return id;
}
public void setId(int id) {
    this.id = id;
}
@Override
public String toString() {
    return "User [name=" + name + ", id=" + id + "]";
}
@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + id;
    result = prime * result + ((name == null) ? 0 : name.hashCode());
    return result;
}
@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    User other = (User) obj;
    if (id != other.id)
        return false;
    if (name == null) {
        if (other.name != null)
            return false;
    } else if (!name.equals(other.name))
        return false;
    return true;


    }
 }

If you have duplicate keys and only a small set of data (<1000) and your code is not performance critical you can just do the following:如果您有重复的键并且只有一小组数据(<1000)并且您的代码不是性能关键,您可以执行以下操作:

Map<String,Integer> tempMap=new HashMap<String,Integer>(inputUnsortedMap);
LinkedHashMap<String,Integer> sortedOutputMap=new LinkedHashMap<String,Integer>();

for(int i=0;i<inputUnsortedMap.size();i++){
    Map.Entry<String,Integer> maxEntry=null;
    Integer maxValue=-1;
    for(Map.Entry<String,Integer> entry:tempMap.entrySet()){
        if(entry.getValue()>maxValue){
            maxValue=entry.getValue();
            maxEntry=entry;
        }
    }
    tempMap.remove(maxEntry.getKey());
    sortedOutputMap.put(maxEntry.getKey(),maxEntry.getValue());
}

inputUnsortedMap is the input to the code. inputUnsortedMap是代码的输入。

The variable sortedOutputMap will contain the data in decending order when iterated over.变量sortedOutputMap将在迭代时按降序包含数据。 To change order just change > to a < in the if statement.要更改顺序,只需在 if 语句中将 > 更改为 <。

Is not the fastest sort but does the job without any additional dependencies.不是最快的排序,但可以在没有任何额外依赖项的情况下完成这项工作。

When I'm faced with this, I just create a list on the side.当我遇到这个问题时,我只是在旁边创建一个列表。 If you put them together in a custom Map implementation, it'll have a nice feel to it... You can use something like the following, performing the sort only when needed.如果你把它们放在一个自定义的 Map 实现中,它会有一个很好的感觉......你可以使用类似下面的东西,只在需要时执行排序。 (Note: I haven't really tested this, but it compiles... might be a silly little bug in there somewhere) (注意:我还没有真正测试过这个,但它编译......可能是某个地方的一个愚蠢的小错误)

(If you want it sorted by both keys and values, have the class extend TreeMap, don't define the accessor methods, and have the mutators call super.xxxxx instead of map_.xxxx) (如果你希望它同时按键和值排序,让类扩展 TreeMap,不要定义访问器方法,并让 mutators 调用 super.xxxx 而不是 map_.xxxx)

package com.javadude.sample;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class SortedValueHashMap<K, V> implements Map<K, V> {
    private Map<K, V> map_ = new HashMap<K, V>();
    private List<V> valueList_ = new ArrayList<V>();
    private boolean needsSort_ = false;
    private Comparator<V> comparator_;

    public SortedValueHashMap() {
    }
    public SortedValueHashMap(List<V> valueList) {
        valueList_ = valueList;
    }

    public List<V> sortedValues() {
        if (needsSort_) {
            needsSort_ = false;
            Collections.sort(valueList_, comparator_);
        }
        return valueList_;
    }

    // mutators
    public void clear() {
        map_.clear();
        valueList_.clear();
        needsSort_ = false;
    }

    public V put(K key, V value) {
        valueList_.add(value);
        needsSort_ = true;
        return map_.put(key, value);
    }

    public void putAll(Map<? extends K, ? extends V> m) {
        map_.putAll(m);
        valueList_.addAll(m.values());
        needsSort_ = true;
    }

    public V remove(Object key) {
        V value = map_.remove(key);
        valueList_.remove(value);
        return value;
    }

    // accessors
    public boolean containsKey(Object key)           { return map_.containsKey(key); }
    public boolean containsValue(Object value)       { return map_.containsValue(value); }
    public Set<java.util.Map.Entry<K, V>> entrySet() { return map_.entrySet(); }
    public boolean equals(Object o)                  { return map_.equals(o); }
    public V get(Object key)                         { return map_.get(key); }
    public int hashCode()                            { return map_.hashCode(); }
    public boolean isEmpty()                         { return map_.isEmpty(); }
    public Set<K> keySet()                           { return map_.keySet(); }
    public int size()                                { return map_.size(); }
    public Collection<V> values()                    { return map_.values(); }
}

The simplest brute-force sortHashMap method for HashMap<String, Long> : you can just copypaste it and use like this: HashMap<String, Long>最简单的蛮力sortHashMap方法:您可以复制粘贴它并像这样使用

public class Test  {
    public static void main(String[] args)  {
        HashMap<String, Long> hashMap = new HashMap<>();
        hashMap.put("Cat", (long) 4);
        hashMap.put("Human", (long) 2);
        hashMap.put("Dog", (long) 4);
        hashMap.put("Fish", (long) 0);
        hashMap.put("Tree", (long) 1);
        hashMap.put("Three-legged-human", (long) 3);
        hashMap.put("Monkey", (long) 2);

        System.out.println(hashMap);  //{Human=2, Cat=4, Three-legged-human=3, Monkey=2, Fish=0, Tree=1, Dog=4}
        System.out.println(sortHashMap(hashMap));  //{Cat=4, Dog=4, Three-legged-human=3, Human=2, Monkey=2, Tree=1, Fish=0}
    }

    public LinkedHashMap<String, Long> sortHashMap(HashMap<String, Long> unsortedMap)  {
        LinkedHashMap<String, Long> result = new LinkedHashMap<>();

        //add String keys to an array: the array would get sorted, based on those keys' values
        ArrayList<String> sortedKeys = new ArrayList<>();
        for (String key: unsortedMap.keySet())  {
            sortedKeys.add(key);
        }

        //sort the ArrayList<String> of keys    
        for (int i=0; i<unsortedMap.size(); i++)  {
            for (int j=1; j<sortedKeys.size(); j++)  {
                if (unsortedMap.get(sortedKeys.get(j)) > unsortedMap.get(sortedKeys.get(j-1))) {
                    String temp = sortedKeys.get(j);
                    sortedKeys.set(j, sortedKeys.get(j-1));
                    sortedKeys.set(j-1, temp);
                }
            }
        }

        // construct the result Map
        for (String key: sortedKeys)  {
            result.put(key, unsortedMap.get(key));
        }

        return result;
    }
}

posting my version of answer发布我的答案版本

List<Map.Entry<String, Integer>> list = new ArrayList<>(map.entrySet());
    Collections.sort(list, (obj1, obj2) -> obj2.getValue().compareTo(obj1.getValue()));
    Map<String, Integer> resultMap = new LinkedHashMap<>();
    list.forEach(arg0 -> {
        resultMap.put(arg0.getKey(), arg0.getValue());
    });
    System.out.println(resultMap);

Using LinkedList使用链表

//Create a list by HashMap
List<Map.Entry<String, Double>> list = new LinkedList<>(hashMap.entrySet());

//Sorting the list
Collections.sort(list, new Comparator<Map.Entry<String, Double>>() {
    public int compare(Map.Entry<String, Double> o1, Map.Entry<String, Double> o2) {
        return (o1.getValue()).compareTo(o2.getValue());
    }
});

//put data from sorted list to hashmap
HashMap<String, Double> sortedData = new LinkedHashMap<>();
for (Map.Entry<String, Double> data : list) {
    sortedData.put(data.getKey(), data.getValue());
}

System.out.print(sortedData);

This has the added benefit of being able to sort ascending or descending, using Java 8这具有能够使用 Java 8 进行升序或降序排序的额外好处

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

create new class创建新班级

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());
    }
}
    Map<String, Integer> map = new HashMap<>();
    map.put("b", 2);
    map.put("a", 1);
    map.put("d", 4);
    map.put("c", 3);
    
    // ----- Using Java 7 -------------------
    List<Map.Entry<String, Integer>> entries = new ArrayList<>(map.entrySet());
    Collections.sort(entries, (o1, o2) -> o1.getValue().compareTo(o2.getValue()));
    System.out.println(entries); // [a=1, b=2, c=3, d=4]


    // ----- Using Java 8 Stream API --------
   map.entrySet().stream().sorted(Map.Entry.comparingByValue()).forEach(System.out::println); // {a=1, b=2, c=3, d=4}

    

This method will just serve the purpose.这种方法只是为了达到目的。 (the 'setback' is that the Values must implement the java.util.Comparable interface ) (“挫折”是 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 http://javawithswranga.blogspot.com/2011/06/generic-method-to-sort-hashmap.html

My solution is a quite simple approach in the way of using mostly given APIs.我的解决方案是使用大多数给定 API 的一种非常简单的方法。 We use the feature of Map to export its content as Set via entrySet() method.我们使用Map的特性通过entrySet()方法将其内容导出为Set We now have a Set containing Map.Entry objects.我们现在有一个包含Map.Entry对象的Set

Okay, a Set does not carry an order, but we can take the content an put it into an ArrayList .好的,一个 Set 不携带订单,但我们可以将内容放入一个ArrayList It now has an random order, but we will sort it anyway.它现在有一个随机顺序,但无论如何我们都会对其进行排序。

As ArrayList is a Collection , we now use the Collections.sort() method to bring order to chaos.由于ArrayList是一个Collection ,我们现在使用Collections.sort()方法来使秩序混乱。 Because our Map.Entry objects do not realize the kind of comparison we need, we provide a custom Comparator .因为我们的Map.Entry对象没有实现我们需要的那种比较,所以我们提供了一个自定义的Comparator

public static void main(String[] args) {
    HashMap<String, String> map = new HashMap<>();
    map.put("Z", "E");
    map.put("G", "A");
    map.put("D", "C");
    map.put("E", null);
    map.put("O", "C");
    map.put("L", "D");
    map.put("Q", "B");
    map.put("A", "F");
    map.put(null, "X");
    MapEntryComparator mapEntryComparator = new MapEntryComparator();

    List<Entry<String,String>> entryList = new ArrayList<>(map.entrySet());
    Collections.sort(entryList, mapEntryComparator);

    for (Entry<String, String> entry : entryList) {
        System.out.println(entry.getKey() + " : " + entry.getValue());
    }

}

If there is a preference of having a Map data structure that inherently sorts by values without having to trigger any sort methods or explicitly pass to a utility, then the following solutions may be applicable:如果有偏好的Map数据结构本质上按值排序,而无需触发任何排序方法或显式传递给实用程序,则以下解决方案可能适用:

(1) org.drools.chance.core.util.ValueSortedMap (JBoss project) maintains two maps internally one for lookup and one for maintaining the sorted values. (1) org.drools.chance.core.util.ValueSortedMap (JBoss 项目)在内部维护两个映射,一个用于查找,一个用于维护排序值。 Quite similar to previously added answers, but probably it is the abstraction and encapsulation part (including copying mechanism) that makes it safer to use from the outside.与之前添加的答案非常相似,但可能是抽象和封装部分(包括复制机制)使其从外部使用更安全。

(2) http://techblog.molindo.at/2008/11/java-map-sorted-by-value.html avoids maintaining two maps and instead relies/extends from Apache Common's LinkedMap. (2) http://techblog.molindo.at/2008/11/java-map-sorted-by-value.html避免维护两个地图,而是依赖/扩展 Apache Common 的 LinkedMap。 (Blog author's note: as all the code here is in the public domain ): (博客作者注: as all the code here is in the public domain ):

// required to access LinkEntry.before and LinkEntry.after
package org.apache.commons.collections.map;

// SNIP: imports

/**
* map implementation based on LinkedMap that maintains a sorted list of
* values for iteration
*/
public class ValueSortedHashMap extends LinkedMap {
    private final boolean _asc;

    // don't use super()!
    public ValueSortedHashMap(final boolean asc) {
        super(DEFAULT_CAPACITY);
        _asc = asc;
    }

    // SNIP: some more constructors with initial capacity and the like

    protected void addEntry(final HashEntry entry, final int hashIndex) {
        final LinkEntry link = (LinkEntry) entry;
        insertSorted(link);
        data[hashIndex] = entry;
    }

    protected void updateEntry(final HashEntry entry, final Object newValue) {
        entry.setValue(newValue);
        final LinkEntry link = (LinkEntry) entry;
        link.before.after = link.after;
        link.after.before = link.before;
        link.after = link.before = null;
        insertSorted(link);
    }

    private void insertSorted(final LinkEntry link) {
        LinkEntry cur = header;
        // iterate whole list, could (should?) be replaced with quicksearch
        // start at end to optimize speed for in-order insertions
        while ((cur = cur.before) != header & amp; & amp; !insertAfter(cur, link)) {}
        link.after = cur.after;
        link.before = cur;
        cur.after.before = link;
        cur.after = link;
    }

    protected boolean insertAfter(final LinkEntry cur, final LinkEntry link) {
        if (_asc) {
            return ((Comparable) cur.getValue())
            .compareTo((V) link.getValue()) & lt; = 0;
        } else {
            return ((Comparable) cur.getValue())
            .compareTo((V) link.getValue()) & gt; = 0;
        }
    }

    public boolean isAscending() {
        return _asc;
    }
}

(3) Write a custom Map or extends from LinkedHashMap that will only sort during enumeration (eg, values() , keyset() , entryset() ) as needed. (3) 编写自定义Map或从LinkedHashMap扩展,仅在枚举期间根据需要进行排序(例如values() ) 、 keyset( keyset()entryset() )。 The inner implementation/behavior is abstracted from the one using this class but it appears to the client of this class that values are always sorted when requested for enumeration.内部实现/行为是从使用此类的实现/行为中抽象出来的,但对于此类的客户来说,在请求枚举时总是对值进行排序。 This class hopes that sorting will happen mostly once if all put operations have been completed before enumerations.这个类希望如果在枚举之前所有的put操作都已经完成,那么排序将主要发生一次。 Sorting method adopts some of the previous answers to this question.排序方法采用了该问题的一些先前答案。

public class SortByValueMap<K, V> implements Map<K, V> {

    private boolean isSortingNeeded = false;

    private final Map<K, V> map = new LinkedHashMap<>();

    @Override
    public V put(K key, V value) {
        isSortingNeeded = true;
        return map.put(key, value);
    }

    @Override
    public void putAll(Map<? extends K, ? extends V> map) {
        isSortingNeeded = true;
        map.putAll(map);
    }

    @Override
    public Set<K> keySet() {
        sort();
        return map.keySet();
    }

    @Override
    public Set<Entry<K, V>> entrySet() {
        sort();
        return map.entrySet();
    }

    @Override
    public Collection<V> values() {
        sort();
        return map.values();
    }

    private void sort() {
        if (!isSortingNeeded) {
            return;
        }

        List<Entry<K, V>> list = new ArrayList<>(size());

        for (Iterator<Map.Entry<K, V>> it = map.entrySet().iterator(); it.hasNext();) {
            Map.Entry<K, V> entry = it.next();
            list.add(entry);
            it.remove();
        }

        Collections.sort(list);

        for (Entry<K, V> entry : list) {
            map.put(entry.getKey(), entry.getValue());
        }

        isSortingNeeded = false;
    }

    @Override
    public String toString() {
        sort();
        return map.toString();
    }
}

(4) Guava offers ImmutableMap.Builder.orderEntriesByValue(Comparator valueComparator) although the resulting map will be immutable: (4) Guava 提供ImmutableMap.Builder.orderEntriesByValue(Comparator valueComparator)虽然结果映射是不可变的:

Configures this Builder to order entries by value according to the specified comparator.将此 Builder 配置为根据指定的比较器按值对条目进行排序。

The sort order is stable, that is, if two entries have values that compare as equivalent, the entry that was inserted first will be first in the built map's iteration order.排序顺序是稳定的,也就是说,如果两个条目的值比较相等,则首先插入的条目将在构建映射的迭代顺序中排在第一位。

I rewrote devinmoore's method that performs sorting a map by it's value without using Iterator :我重写了 devinmoore 的方法,该方法在不使用 Iterator 的情况下按其值对地图进行排序:

public static Map<K, V> sortMapByValue(Map<K, V> inputMap) {

    Set<Entry<K, V>> set = inputMap.entrySet();
    List<Entry<K, V>> list = new ArrayList<Entry<K, V>>(set);

    Collections.sort(list, new Comparator<Map.Entry<K, V>>()
    {
        @Override
        public int compare(Entry<K, V> o1, Entry<K, V> o2) {
            return (o1.getValue()).compareTo( o2.getValue() );  //Ascending order
        }
    } );

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

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

    return sortedMap;
}

Note: that we used LinkedHashMap as output map, because our list has been sorted by value and now we should store our list into output map with order of inserted key,values. Note:我们使用LinkedHashMap作为输出映射,因为我们的列表已经按值排序,现在我们应该按照插入键值的顺序将列表存储到输出映射中。 So if you use for example TreeMap as your output map, your map will be sorted by map keys again!因此,如果您使用例如TreeMap作为输出地图,您的地图将再次按地图键排序!

This is the main method:这是主要方法:

public static void main(String[] args) {
    Map<String, String> map = new HashMap<>();
    map.put("3", "three");
    map.put("1", "one");
    map.put("5", "five");
    System.out.println("Input Map:" + map);
    System.out.println("Sorted Map:" + sortMapByValue(map));
}

Finally, this is the output:最后,这是输出:

Input Map:{1=one, 3=three, 5=five}
Sorted Map:{5=five, 1=one, 3=three}

Using Guava library:使用番石榴库:

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

creates a list of entries for each value, where the values are sorted为每个值创建一个条目列表,其中对值进行排序
requires Java 8 or above需要 Java 8 或更高版本

Map<Double,List<Entry<String,Double>>> sorted =
map.entrySet().stream().collect( Collectors.groupingBy( Entry::getValue, TreeMap::new,
    Collectors.mapping( Function.identity(), Collectors.toList() ) ) );

using the map {[A=99.5], [B=67.4], [C=67.4], [D=67.3]}使用地图 {[A=99.5], [B=67.4], [C=67.4], [D=67.3]}
gets {67.3=[D=67.3], 67.4=[B=67.4, C=67.4], 99.5=[A=99.5]}得到{67.3=[D=67.3], 67.4=[B=67.4, C=67.4], 99.5=[A=99.5]}


…and how to access each entry one after the other: …以及如何一个接一个地访问每个条目:

sorted.entrySet().forEach( e -> e.getValue().forEach( l -> System.out.println( l ) ) );

D=67.3 B=67.4 C=67.4 A=99.5 D=67.3 B=67.4 C=67.4 A=99.5

I can give you an example but sure this is what you need.我可以给你一个例子,但肯定这是你需要的。

map = {10 = 3, 11 = 1,12 = 2} 

Let's say you want the top 2 most frequent key which is (10, 12) So the easiest way is using a PriorityQueue to sort based on the value of the map.假设您想要前 2 个最常用的键,即 (10, 12) 所以最简单的方法是使用 PriorityQueue 根据地图的值进行排序。

PriorityQueue<Integer> pq = new PriorityQueue<>((a, b) -> (map.get(a) - map.get(b));
for(int key: map.keySets()) {
   pq.add(key);
   if(pq.size() > 2) {
      pq.poll();
   }
}
// Now pq has the top 2 most frequent key based on value. It sorts the value. 

In TreeMap, keys are sorted in natural order.在 TreeMap 中,键按自然顺序排序。 For example, if you sorting numbers, (notice the ordering of 4 )例如,如果您对数字进行排序,(请注意4的排序)

{0=0, 10=10, 20=20, 30=30, 4=4, 50=50, 60=60, 70=70}

To fix this, In Java8, first check string length and then compare.为了解决这个问题,在 Java8 中,首先检查字符串长度,然后进行比较。

Map<String, String> sortedMap = new TreeMap<>Comparator.comparingInt(String::length)
.thenComparing(Function.identity()));

{0=0, 4=4, 10=10, 20=20, 30=30, 50=50, 60=60, 70=70}

Here's a generic-friendly version:这是一个通用的友好版本:

public class MapUtil {
    public static <K, V extends Comparable<? super V>> Map<K, V> sortByValue(Map<K, V> map) {
        List<Entry<K, V>> list = new ArrayList<>(map.entrySet());
        list.sort(Entry.comparingByValue());

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

        return result;
    }
}
public class Test {
  public static void main(String[] args) {
    TreeMap<Integer, String> hm=new TreeMap();
    hm.put(3, "arun singh");
    hm.put(5, "vinay singh");
    hm.put(1, "bandagi singh");
    hm.put(6, "vikram singh");
    hm.put(2, "panipat singh");
    hm.put(28, "jakarta singh");

    ArrayList<String> al=new ArrayList(hm.values());
    Collections.sort(al, new myComparator());

    System.out.println("//sort by values \n");
    for(String obj: al){
        for(Map.Entry<Integer, String> map2:hm.entrySet()){
            if(map2.getValue().equals(obj)){
                System.out.println(map2.getKey()+" "+map2.getValue());
            }
        } 
     }
  }
}

class myComparator implements Comparator{
    @Override
    public int compare(Object o1, Object o2) {
       String o3=(String) o1;
       String o4 =(String) o2;
       return o3.compareTo(o4);
    }   
}

OUTPUT=输出=

//sort by values 

3 arun singh
1 bandagi singh
28 jakarta singh
2 panipat singh
6 vikram singh
5 vinay singh

Geeks For Geeks on sorting the HashMap by Value Geeks For Geeks 按值对 HashMap 进行排序

Input : Key = Math, Value = 98
    Key = Data Structure, Value = 85
    Key = Database, Value = 91
    Key = Java, Value = 95
    Key = Operating System, Value = 79
    Key = Networking, Value = 80

Output : Key = Operating System, Value = 79
         Key = Networking, Value = 80
         Key = Data Structure, Value = 85
         Key = Database, Value = 91
         Key = Java, Value = 95
         Key = Math, Value = 98
Solution: The idea is to store the entry set in a list and sort the list on the basis of values. Then fetch values and keys from the list and put them in a new hashmap. Thus, a new hashmap is sorted according to values.
Below is the implementation of the above idea: 




// Java program to sort hashmap by values
import java.util.*;
import java.lang.*;
 
public class GFG {
 
    // function to sort hashmap by values
    public static HashMap<String, Integer> sortByValue(HashMap<String, Integer> hm)
    {
        // Create a list from elements of HashMap
        List<Map.Entry<String, Integer> > list =
               new LinkedList<Map.Entry<String, Integer> >(hm.entrySet());
 
        // Sort the list
        Collections.sort(list, new Comparator<Map.Entry<String, Integer> >() {
            public int compare(Map.Entry<String, Integer> o1,
                               Map.Entry<String, Integer> o2)
            {
                return (o1.getValue()).compareTo(o2.getValue());
            }
        });
         
        // put data from sorted list to hashmap
        HashMap<String, Integer> temp = new LinkedHashMap<String, Integer>();
        for (Map.Entry<String, Integer> aa : list) {
            temp.put(aa.getKey(), aa.getValue());
        }
        return temp;
    }
 
    // Driver Code
    public static void main(String[] args)
    {
 
        HashMap<String, Integer> hm = new HashMap<String, Integer>();
 
        // enter data into hashmap
        hm.put("Math", 98);
        hm.put("Data Structure", 85);
        hm.put("Database", 91);
        hm.put("Java", 95);
        hm.put("Operating System", 79);
        hm.put("Networking", 80);
        Map<String, Integer> hm1 = sortByValue(hm);
 
        // print the sorted hashmap
        for (Map.Entry<String, Integer> en : hm1.entrySet()) {
            System.out.println("Key = " + en.getKey() +
                          ", Value = " + en.getValue());
        }
    }
}
Output
Key = Operating System, Value = 79
Key = Networking, Value = 80
Key = Data Structure, Value = 85
Key = Database, Value = 91
Key = Java, Value = 95
Key = Math, Value = 98
public class SortedMapExample {

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

        map.put("Cde", "C");
        map.put("Abc", "A");
        map.put("Cbc", "Z");
        map.put("Dbc", "D");
        map.put("Bcd", "B");
        map.put("sfd", "Bqw");
        map.put("DDD", "Bas");
        map.put("BGG", "Basd");

        System.out.println(sort(map, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                    return o1.compareTo(o2);
            }}));
    }

    @SuppressWarnings("unchecked")
    public static <K, V> Map<K,V> sort(Map<K, V> in, Comparator<? super V> compare) {
        Map<K, V> result = new LinkedHashMap<K, V>();
        V[] array = (V[])in.values().toArray();
        for(int i=0;i<array.length;i++)
        {

        }
        Arrays.sort(array, compare);
        for (V item : array) {
            K key= (K) getKey(in, item);
            result.put(key, item);
        }
        return result;
    }

    public static <K, V>  Object getKey(Map<K, V> in,V value)
    {
       Set<K> key= in.keySet();
       Iterator<K> keyIterator=key.iterator();
       while (keyIterator.hasNext()) {
           K valueObject = (K) keyIterator.next();
           if(in.get(valueObject).equals(value))
           {
                   return valueObject;
           }
       }
       return null;
   }

} }

// Please try here. // 请在这里尝试。 I am modifing the code for value sort.我正在修改值排序的代码。

For sorting upon the keys I found a better solution with a TreeMap (I will try to get a solution for value based sorting ready too):为了对键进行排序,我找到了一个更好的 TreeMap 解决方案(我也会尝试为基于值的排序准备一个解决方案):

public static void main(String[] args) {
    Map<String, String> unsorted = new HashMap<String, String>();
    unsorted.put("Cde", "Cde_Value");
    unsorted.put("Abc", "Abc_Value");
    unsorted.put("Bcd", "Bcd_Value");

    Comparator<String> comparer = new Comparator<String>() {
        @Override
        public int compare(String o1, String o2) {
            return o1.compareTo(o2);
        }};

    Map<String, String> sorted = new TreeMap<String, String>(comparer);
    sorted.putAll(unsorted);
    System.out.println(sorted);
}

Output would be:输出将是:

{Abc=Abc_Value, Bcd=Bcd_Value, Cde=Cde_Value} {Abc=Abc_Value, Bcd=Bcd_Value, Cde=Cde_Value}

Okay, this version works with two new Map objects and two iterations and sorts on values.好的,这个版本适用于两个新的 Map 对象和两个迭代和值排序。 Hope, the performs well although the map entries must be looped twice:希望,尽管映射条目必须循环两次,但性能良好:

public static void main(String[] args) {
    Map<String, String> unsorted = new HashMap<String, String>();
    unsorted.put("Cde", "Cde_Value");
    unsorted.put("Abc", "Abc_Value");
    unsorted.put("Bcd", "Bcd_Value");

    Comparator<String> comparer = new Comparator<String>() {
        @Override
        public int compare(String o1, String o2) {
            return o1.compareTo(o2);
        }};

    System.out.println(sortByValue(unsorted, comparer));

}

public static <K, V> Map<K,V> sortByValue(Map<K, V> in, Comparator<? super V> compare) {
    Map<V, K> swapped = new TreeMap<V, K>(compare);
    for(Entry<K,V> entry: in.entrySet()) {
        if (entry.getValue() != null) {
            swapped.put(entry.getValue(), entry.getKey());
        }
    }
    LinkedHashMap<K, V> result = new LinkedHashMap<K, V>();
    for(Entry<V,K> entry: swapped.entrySet()) {
        if (entry.getValue() != null) {
            result.put(entry.getValue(), entry.getKey());
        }
    }
    return result;
}

The solution uses a TreeMap with a Comparator and sorts out all null keys and values.该解决方案使用带有 Comparator 的 TreeMap 并整理出所有空键和值。 First, the ordering functionality from the TreeMap is used to sort upon the values, next the sorted Map is used to create a result as a LinkedHashMap that retains has the same order of values.首先,来自 TreeMap 的排序功能用于对值进行排序,接下来,排序后的 Map 用于创建一个结果,作为保持具有相同值顺序的 LinkedHashMap。

Greetz, GHad格瑞兹,GHad

If there's not any value bigger than the size of the map, you could use arrays, this should be the fastest approach:如果没有任何值大于地图的大小,则可以使用数组,这应该是最快的方法:

public List<String> getList(Map<String, Integer> myMap) {
    String[] copyArray = new String[myMap.size()];
    for (Entry<String, Integer> entry : myMap.entrySet()) {
        copyArray[entry.getValue()] = entry.getKey();
    }
    return Arrays.asList(copyArray);
}
    static <K extends Comparable<? super K>, V extends Comparable<? super V>>
    Map sortByValueInDescendingOrder(final Map<K, V> map) {
        Map re = new TreeMap(new Comparator<K>() {
            @Override
            public int compare(K o1, K o2) {
                if (map.get(o1) == null || map.get(o2) == null) {
                    return -o1.compareTo(o2);
                }
                int result = -map.get(o1).compareTo(map.get(o2));
                if (result != 0) {
                    return result;
                }
                return -o1.compareTo(o2);
            }
        });
        re.putAll(map);
        return re;
    }
    @Test(timeout = 3000l, expected = Test.None.class)
    public void testSortByValueInDescendingOrder() {
        char[] arr = "googler".toCharArray();
        Map<Character, Integer> charToTimes = new HashMap();
        for (int i = 0; i < arr.length; i++) {
            Integer times = charToTimes.get(arr[i]);
            charToTimes.put(arr[i], times == null ? 1 : times + 1);
        }
        Map sortedByTimes = sortByValueInDescendingOrder(charToTimes);
        Assert.assertEquals(charToTimes.toString(), "{g=2, e=1, r=1, o=2, l=1}");
        Assert.assertEquals(sortedByTimes.toString(), "{o=2, g=2, r=1, l=1, e=1}");
        Assert.assertEquals(sortedByTimes.containsKey('a'), false);
        Assert.assertEquals(sortedByTimes.get('a'), null);
        Assert.assertEquals(sortedByTimes.get('g'), 2);
        Assert.assertEquals(sortedByTimes.equals(charToTimes), true);
    }

We simply sort a map just like this我们只是像这样对地图进行排序

            Map<String, String> unsortedMap = new HashMap<String, String>();

    unsortedMap.put("E", "E Val");
    unsortedMap.put("F", "F Val");
    unsortedMap.put("H", "H Val");
    unsortedMap.put("B", "B Val");
    unsortedMap.put("C", "C Val");
    unsortedMap.put("A", "A Val");
    unsortedMap.put("G", "G Val");
    unsortedMap.put("D", "D Val");

    Map<String, String> sortedMap = new TreeMap<String, String>(unsortedMap);

    System.out.println("\nAfter sorting..");
    for (Map.Entry <String, String> mapEntry : sortedMap.entrySet()) {
        System.out.println(mapEntry.getKey() + " \t" + mapEntry.getValue());

Best thing is to convert HashMap to TreeMap.最好的办法是将 HashMap 转换为 TreeMap。 TreeMap sort keys on its own. TreeMap 自行排序键。 If you want to sort on values than quick fix can be you can switch values with keys if your values are not duplicates.如果您想对值进行排序而不是快速修复,如果您的值不重复,您可以使用键切换值。

If your Map values implement Comparable (eg String), this should work如果您的 Map 值实现 Comparable(例如 String),这应该可以

Map<Object, String> map = new HashMap<Object, String>();
// Populate the Map
List<String> mapValues = new ArrayList<String>(map.values());
Collections.sort(mapValues);

If the map values themselves don't implement Comparable, but you have an instance of Comparable that can sort them, replace the last line with this:如果地图值本身没有实现 Comparable,但您有一个可以对它们进行排序的 Comparable 实例,请将最后一行替换为:

Collections.sort(mapValues, comparable);

as map is unordered to sort it ,we can do following由于地图是无序排序的,我们可以做以下

Map<String, String> map= new TreeMap<String, String>(unsortMap);

You should note that, unlike a hash map, a tree map guarantees that its elements will be sorted in ascending key order.您应该注意,与哈希映射不同,树映射保证其元素将按键升序排序。

Use java.util.TreeMap .使用java.util.TreeMap

"The map is sorted according to the natural ordering of its keys, or by a Comparator provided at map creation time, depending on which constructor is used." “地图根据其键的自然顺序排序,或者由地图创建时提供的比较器排序,具体取决于使用的构造函数。”

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM