【问题标题】:Get minvalue of a Map(Key,Double)获取地图的最小值(键,双)
【发布时间】:2011-02-16 02:21:45
【问题描述】:

是否有方法(可能使用 Google Collections)来获取 Map(Key, Double) 的最小值?

以传统方式,我必须根据值对地图进行排序,然后取第一个/最后一个。

【问题讨论】:

    标签: java guava


    【解决方案1】:

    您可以为此使用标准的Collections#min()

    Map<String, Double> map = new HashMap<String, Double>();
    map.put("1.1", 1.1);
    map.put("0.1", 0.1);
    map.put("2.1", 2.1);
    
    Double min = Collections.min(map.values());
    System.out.println(min); // 0.1
    

    更新:既然您也需要密钥,那么我在Collections 或Google Collections2 API 中看不到方法,因为Map 不是CollectionMaps#filterEntries() 也不是很有用,因为您只知道迭代结束时的实际结果。

    最直接的解决方案是:

    Entry<String, Double> min = null;
    for (Entry<String, Double> entry : map.entrySet()) {
        if (min == null || min.getValue() > entry.getValue()) {
            min = entry;
        }
    }
    
    System.out.println(min.getKey()); // 0.1
    

    (对min 进行空检查)

    【讨论】:

    • 感谢您的回答-我忘了提到我需要最小值的键
    • 非常感谢,顺便说一句,我还需要获得排序地图的排名。我想将索引用作排名 (1,2,3...) 使用地图执行此操作的最佳方法可能是什么,因为此处无法获取索引。每次都从地图中创建一个列表相当不方便
    • 如果你想要一个索引,你真的需要使用List&lt;SomeObject&gt;,而不是结合一个合适的Comparator&lt;SomeObject&gt;或者Comparable&lt;SomeObject&gt;。然后SomeObject 可以保存原始映射键和值。 Set&lt;SomeObject&gt; 也可能合适,你自己算索引吧。
    【解决方案2】:

    您仍然可以使用 Collections.min 和自定义 Comparator 来获得具有较低值的 Map.Entry

    Map<String, Double> map = new HashMap<String, Double>();
    map.put("1.1", 1.1);
    map.put("0.1", 0.1);
    map.put("2.1", 2.1);
    Entry<String, Double> min = Collections.min(map.entrySet(), new Comparator<Entry<String, Double>>() {
        public int compare(Entry<String, Double> entry1, Entry<String, Double> entry2) {
            return entry1.getValue().compareTo(entry2.getValue());
        }
    });
    System.out.printf("%s: %f", min.getKey(), min.getValue()); // 0.1: 0.100000
    

    使用 Java 8:

    Entry<String, Double> min = Collections.min(map.entrySet(),
                                           Comparator.comparing(Entry::getValue));
    

    【讨论】:

      【解决方案3】:

      Java8 单行器

      Key key = Collections.min(map.entrySet(), Map.Entry.comparingByValue()).getKey()
      

      【讨论】:

        【解决方案4】:

        以传统方式,我必须 根据值对地图进行排序, 并采取第一个/最后一个。谢谢

        不,你不会。您必须遍历所有值,并在每一步将当前元素与迄今为止看到的最小元素进行比较。这是 O(n),与 O(n*log(n)) 进行排序相比 - 一个潜在的巨大差异。

        顺便说一句,这正是Collections.min() 的工作原理。

        【讨论】:

        • 如果我根据值对地图进行排序,我会得到一个新的排序地图,例如:(A,1),(B,2),(C,3) 这里可以取只是第一个元素的键。
        • @chris-gr:它需要的时间更长,并且使用的内存比必要的多。
        【解决方案5】:

        使用 Java 8 流:

        return map
                    .entrySet()
                    .stream()
                    .sorted(Comparator.comparingDouble(Map.Entry::getValue))
                    .findFirst()
                    .map(Map.Entry::getValue);
        

        或者

        return map
                    .entrySet()
                    .stream()
                    .min(Comparator.comparingDouble(Map.Entry::getValue))
                    .map(Map.Entry::getValue);
        

        但如果你想多次这样做,那么一定要给heap看看。

        【讨论】:

          【解决方案6】:

          我倾向于使用 Google Collections BiMap:

               String minKey = HashBiMap.create(map).inverse().get(Collections.min(map.values()));
          

          或类似的东西(未测试)。

          【讨论】:

          • 不错的 oneliner,但效率不高。
          • 但可能是值相同(双精度)在这种情况下我会得到哪个键?
          • @chris,它与映射中的键和值是什么有关,而不是它们的类型。最后,在运行时,它们无论如何都是对象。
          • @BalusC,当然不是,但这可能无关紧要。如果地图很大并且经常双向使用,则可以首先将其存储在 BiMap 中。 inverse() 在这种情况下是一种廉价的操作。
          【解决方案7】:

          在 Java 8 中我们可以轻松搞定:

          Double minValue = map.entrySet().stream().min(Map.Entry.comparingByValue()).get().getValue();
          Double maxValue = map.entrySet().stream().max(Map.Entry.comparingByValue()).get().getValue();
          

          【讨论】:

          • 不错,但使用 .get() 可能会导致错误。这些会创建一个没有“isPresent()”警告的“Optional.get()”。查看this page 了解一些更安全的替代方案
          【解决方案8】:

          为了有效地完成它,您可能希望定义自己的数据结构,以便它实现 Map 接口,同时也允许高效的 getMin() 操作。

          这可以使用两种内部数据结构来完成:映射和树(或堆数据结构)。每次添加新对 (K,V) 时,将它们添加到地图和树中(作为单个条目)。这使得 get(Key) 操作需要 O(1) 时间,而添加、删除和 getMin 操作需要 O(log n) 时间。

          【讨论】:

            【解决方案9】:

            使用 java 8(和静态导入)。我们可以让@superfav 的解决方案更加整洁:

            Map<String, Double> myMap;
            String theKeyWithHighestValue = Collections.min(myMap.entrySet(), comparingDouble(Entry::getValue)).getKey()
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2019-12-30
              • 1970-01-01
              • 2014-07-07
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多