【发布时间】:2011-02-16 02:21:45
【问题描述】:
是否有方法(可能使用 Google Collections)来获取 Map(Key, Double) 的最小值?
以传统方式,我必须根据值对地图进行排序,然后取第一个/最后一个。
【问题讨论】:
是否有方法(可能使用 Google Collections)来获取 Map(Key, Double) 的最小值?
以传统方式,我必须根据值对地图进行排序,然后取第一个/最后一个。
【问题讨论】:
您可以为此使用标准的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 不是Collection。 Maps#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 进行空检查)
【讨论】:
List<SomeObject>,而不是结合一个合适的Comparator<SomeObject>或者Comparable<SomeObject>。然后SomeObject 可以保存原始映射键和值。 Set<SomeObject> 也可能合适,你自己算索引吧。
您仍然可以使用 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));
【讨论】:
Java8 单行器
Key key = Collections.min(map.entrySet(), Map.Entry.comparingByValue()).getKey()
【讨论】:
以传统方式,我必须 根据值对地图进行排序, 并采取第一个/最后一个。谢谢
不,你不会。您必须遍历所有值,并在每一步将当前元素与迄今为止看到的最小元素进行比较。这是 O(n),与 O(n*log(n)) 进行排序相比 - 一个潜在的巨大差异。
顺便说一句,这正是Collections.min() 的工作原理。
【讨论】:
使用 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看看。
【讨论】:
我倾向于使用 Google Collections BiMap:
String minKey = HashBiMap.create(map).inverse().get(Collections.min(map.values()));
或类似的东西(未测试)。
【讨论】:
在 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 了解一些更安全的替代方案
为了有效地完成它,您可能希望定义自己的数据结构,以便它实现 Map 接口,同时也允许高效的 getMin() 操作。
这可以使用两种内部数据结构来完成:映射和树(或堆数据结构)。每次添加新对 (K,V) 时,将它们添加到地图和树中(作为单个条目)。这使得 get(Key) 操作需要 O(1) 时间,而添加、删除和 getMin 操作需要 O(log n) 时间。
【讨论】:
使用 java 8(和静态导入)。我们可以让@superfav 的解决方案更加整洁:
Map<String, Double> myMap;
String theKeyWithHighestValue = Collections.min(myMap.entrySet(), comparingDouble(Entry::getValue)).getKey()
【讨论】: