【问题标题】:Sorting HashMaps by value按值对 HashMap 进行排序
【发布时间】:2012-02-06 22:26:29
【问题描述】:

当我需要按值对 HashMap 进行排序时,建议似乎是创建 HashMap,然后将数据放入按值排序的 TreeMap。

例如:Sort a Map<Key, Value> by values (Java)

我的问题:为什么有必要这样做?为什么不创建一个 TreeMap(按键排序),然后按值排序?

【问题讨论】:

    标签: java hashmap


    【解决方案1】:

    如果你知道你的值是唯一的,你可以使用 Guava 的BiMap(双向映射)来存储数据。像创建HashMap 一样创建HashBiMap,然后从其逆向创建一个新的TreeMap

    new TreeMap<>(biMap.inverse());
    

    然后该地图将按值排序。请记住,您认为的“键”和“值”将被交换。

    如果您的值不是唯一的,您可以创建逆的多重映射。多重映射本质上是从每个键到一个或多个值的映射。它通常通过制作从键到列表的映射来实现。不过,您不必这样做,因为 Google 为您做到了。只需从您现有的地图创建一个多地图,然后让 Guava 为您将其反转为 TreeMultimap,您可以猜到,这是一个 TreeMap,每个键可以保存多个值。

    Multimaps.invertFrom(Multimaps.forMap(myMap), new TreeMultimap<V, K>());
    

    Multimap documentation is provided.

    【讨论】:

    • 唉,我的价值观可能不是独一无二的,但我会牢记这一点。
    【解决方案2】:

    因为您无法手动重新排序 TreeMap 的条目。 TreeMap 条目总是按键排序。

    我将扔掉Map that could be iterated in the order of values 作为“如何做”的另一个答案...具体来说,一个解决方案不会返回一个在查询键时阻塞(通过抛出异常)的映射不在您的原始地图中。

    【讨论】:

    • 请注意,如果您费心阅读 OP 中引用的问题,您会注意到 TreeMaps not 总是按键排序. Treemaps 可以接受一个比较器,它允许它们对几乎任何东西(包括值)进行排序。
    • 我认为将值放入数组然后排序可能更容易。
    • @gnomed:TreeMap 总是对键进行排序,尽管它可能会根据一些古怪的比较器进行排序(很可能是从其他地方查找值)。事实上,我确实阅读了 OP 中引用的问题,尽管它提出了一种在您尝试 map.containsKey(keyNotInOriginalMap) 时坦率地说很容易出现古怪错误的技术,突然间您会遇到非常令人困惑的异常并且不知道为什么您会得到他们。
    • @TomKealy:如果您打算采用这种方法,那么有一些方便的方法可以做到——不要使用数组。例如,List&lt;V&gt; theValues = new ArrayList&lt;V&gt;(map.values()); Collections.sort(theValues);
    • 好的,这就是我想做的。但是,我最初的问题是为什么创建一个 HashMap 然后将内容放入 TreeMap 但通过键查找 - 有没有更好的方法可以避免使用两个对象(在 Java 中 - 例如 bash 脚本将在一行中执行此操作) .我这样做的方式似乎有点多余。
    【解决方案3】:

    我有这个运行良好的非常小的代码:

    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 
    

    【讨论】:

      【解决方案4】:

      我使用 Java 8 Stream API 编写了以下单行代码,以按值对任何给定地图进行排序:

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

      【讨论】:

        猜你喜欢
        • 2011-12-28
        • 1970-01-01
        • 1970-01-01
        • 2011-11-05
        • 2023-04-06
        • 2019-04-08
        • 2018-06-06
        • 2015-12-04
        • 2017-09-22
        相关资源
        最近更新 更多