按值对HashMap进行排序

3
当我需要按值对HashMap进行排序时,建议是创建HashMap,然后将数据放入按值排序的TreeMap中。
例如:Sort a Map<Key, Value> by values (Java) 我的问题是:为什么需要这样做?为什么不创建一个按键排序的TreeMap,然后就地按值排序呢?
4个回答

2
如果您知道您的值是唯一的,您可以使用Guava的BiMap(双向映射)来存储数据。像创建HashMap一样创建HashBiMap,然后从其反转创建一个新的TreeMap
new TreeMap<>(biMap.inverse());

那张地图将会按照值进行排序。请记住,你所想的“键”和“值”将被交换。
如果你的值不是唯一的,你可以创建一个反向的 multimap。Multimap 本质上是从每个键到一个或多个值的映射。它通常通过将一个键映射到一个列表来实现。但你不必这样做,因为 Google 已经为你做了。只需从现有的 map 创建一个 multimap,并要求 Guava 将其反转成一个 TreeMultimap,它就像一个 TreeMap 一样,可以在每个键下保存多个值。
Multimaps.invertFrom(Multimaps.forMap(myMap), new TreeMultimap<V, K>());

提供了Multimap文档链接


唉,我的值可能不是唯一的,但我会记住这一点以备将来之需。 - Tom Kealy

2
因为您无法手动重新排序 TreeMap 的条目。 TreeMap 条目始终按键排序。
我将可以按值顺序迭代的 Map抛弃作为另一个回答“如何做到这一点”的答案......具体来说,这是一种不会在查询原始映射中不存在的键时使映射窒息(通过引发异常)的解决方案。

只是提醒一下,如果你有兴趣阅读OP中引用的问题,你会注意到TreeMaps并不总是按键排序。Treemaps可以接受比较器,使它们可以按照几乎任何东西进行排序(包括值)。 - gnomed
1
我认为把这些值放在一个数组里然后排序会更容易。 - Tom Kealy
1
@gnomed:TreeMap总是按键排序,尽管它可能根据某些奇怪的比较器进行排序(这可能完全可能从其他地方查找值)。事实上,我确实阅读了OP中引用的问题,但它提出的技术在尝试map.containsKey(keyNotInOriginalMap)时容易出现奇怪的错误,突然间你会收到非常令人困惑的异常,并且不知道为什么会出现这种情况。 - Louis Wasserman
@TomKealy:如果你要采用这种方法,那么有方便的方式可以实现——不要使用数组。例如,List<V> theValues = new ArrayList<V>(map.values()); Collections.sort(theValues); - Louis Wasserman
好的,这就是我想要做的。然而,我的原始问题是为什么要创建一个HashMap,然后将东西放入TreeMap中,但是通过键查找 - 是否有更好的方法可以避免使用两个对象(在Java中 - 例如bash脚本将在一行中执行此操作)。我现在的方式似乎有点冗余。 - Tom Kealy
没有一种方法可以在没有中间对象的情况下完成它,除非付出大量的努力。 - Louis Wasserman

1

我使用Java 8 Stream API编写了以下一行代码,可以按值对任何给定的映射进行排序:

List<Map.Entry<String, String>> sortedEntries = map.entrySet().stream()
  .sorted((o1, o2) -> o1.getValue().compareTo(o2.getValue())).collect(Collectors.toList());

1
我有一段非常简短的代码,它能够正常工作:
public class SortMapByValues {
    public static void main(String[] args) {

        Map<Integer, String> myMap = new LinkedHashMap<Integer, String>();

        myMap.put(100, "hundread");
        myMap.put(500, "fivehundread");
        myMap.put(250, "twofifty");
        myMap.put(300, "threehundread");
        myMap.put(350, "threefifty");
        myMap.put(400, "fourhundread");

        myMap = sortMapByValues(myMap);

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

    }

    public static Map<Integer, String> sortMapByValues(
            Map<Integer, String> firstMap) {
        Map<String, Integer> SecondyMap = new TreeMap<String, Integer>();

        for (Map.Entry<Integer, String> entry : firstMap.entrySet()) {
            SecondyMap.put(entry.getValue(), entry.getKey());
        }
        firstMap.clear();
        for (Map.Entry<String, Integer> entry : SecondyMap.entrySet()) {
            firstMap.put(entry.getValue(), entry.getKey());
        }
        return firstMap;
    }

}

输出:

500 fivehundread  
400 fourhundread  
100 hundread  
350 threefifty  
300 threehundread  
250 twofifty 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接