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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 20:11:30  来源:igfitidea点击:

Java - Inline definition of comparator for Collection.max

java

提问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 depScoresas 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 Comparatorfrom 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 depScoreare 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 mapnot being finalcan 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();
}