Java - Collection.max 比较器的内联定义
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19785124/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java - Inline definition of comparator for Collection.max
提问by Nullpoet
I am looking for a Java equivalent for python snippet
我正在寻找 Python 代码段的 Java 等价物
max_valued_key = max(str_to_double_map.keys(), key=lambda x: str_to_double_map[x])
I want to something standard like Collections.max
Is there a way to do this with inline definition of Comparatorsince I don't want to write one more class for every other comparator.
我想要像 Collections.max 这样的标准
有没有办法用Comparator 的内联定义来做到这一点,因为我不想为每个其他比较器再写一个类。
I tried following code unsuccessfully
我尝试以下代码失败
depScores = foo();
String dep = Collections.max(depScores.keySet(), new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return depScores.get(o1).compareTo(depScores.get(o2));
}
});
depScores variable is not readable from comparator.
Looks like in java inner class cannot access non-final variable from outside!
depScores 变量无法从比较器读取。
看起来在java内部类中无法从外部访问非最终变量!
Thanks in advance!
提前致谢!
采纳答案by Mike Strobel
Just declare depScores
as a final variable. If for some reason you can't, create a second (final) variable that points to it.
只需声明depScores
为最终变量。如果由于某种原因你不能,创建指向它的第二个(最终)变量。
Local classes can capture variables only if they are final.
局部类只有在它们是 final 时才能捕获变量。
As a (very) late addendum, it is trivial to create a custom Comparator
from a lambda in Java 8:
作为(非常)晚的附录,Comparator
在 Java 8 中从 lambda创建自定义是微不足道的:
String dep = Collections.max(
depScores.keySet(),
Comparator.comparing(k -> depScores.get(k))
);
You can get even more terse by replacing the lambda k -> depScores.get(k)
with the method reference depScores::get
.
通过将 lambda 替换k -> depScores.get(k)
为方法引用,您可以获得更简洁的信息depScores::get
。
The rules for capturing local variables like depScore
are a little more flexible for lambdas than inner classes: captured variables need only be effectively final. In other words, they must be assigned exactly once, though they needn't be explicitly marked final
.
depScore
对于 lambdas 来说,捕获局部变量的规则比内部类更灵活一些:捕获的变量只需要有效的 final。换句话说,它们必须只分配一次,尽管它们不需要显式标记final
。
回答by Holger
What you want is (will be) possible with Java?8:
您想要的是(将)可以使用 Java?8:
Map<String,Double> map…
String maxKey=Collections.max(map.keySet(), (x,y)->Double.compare(map.get(x),map.get(y)));
or even shorter
甚至更短
String maxKey = Collections.max(map.keySet(), Comparator.comparingDouble(map::get));
For previous Java version you have to use:
对于以前的 Java 版本,您必须使用:
String maxKey=Collections.max(map.keySet(), new Comparator<String>(){
public int compare(String x, String y) {
return Double.compare(map.get(x),map.get(y));
}
});
Problems with map
not being final
can be circumvented by assigning it to a final variable right before the invocation:
有问题的map
不是final
可以通过将其分配给调用之前右边最后一个变量被规避:
final Map<String,Double> fmap=map;
String maxKey=Collections.max(map.keySet(), new Comparator<String>(){
public int compare(String x, String y) {
return Double.compare(fmap.get(x),fmap.get(y));
}
});
But I think even more straightforward and more efficient will be the following helper method as it does not require any hash lookups:
但我认为更直接、更有效的是以下辅助方法,因为它不需要任何哈希查找:
static <K,V extends Comparable<V>> K keyForHighestValue(Map<K,V> map) {
V maxValue=Collections.max(map.values());
for(Map.Entry<K,V> e:map.entrySet()) {
if(e.getValue()==maxValue) return e.getKey();
}
throw new ConcurrentModificationException();
}