Java 8哈希映射表

7
我有一个名为Map<String, List<Double>的地图,我想在所有列表中找到最大(或最小)值。该函数应返回最大(或最小)值及其所属键。
签名可以是 public static Pair<String,Double> getKeyValue(Map<String, List<Double>> map, BinaryOperator<Double> function) 它获取地图和函数Double::maxDouble::min 如何使用Java 8、Stream API高效(且美观)地实现此功能?
2个回答

4
你可以尝试这个方法:
public static Pair<String,Double> getKeyValue(Map<String,List<Double>> map,
        BinaryOperator<Double> function) {
        return map.entrySet().stream()
            .map(e -> new Pair<String,Double>(e.getKey(),e.getValue().stream().reduce(function).get()))
            .reduce((p1,p2) -> function.apply(p1.getValue(),p2.getValue()).equals(p1.getValue()) ? p1 : p2)
            .get();
}

解释:

首先,将每个Entry<String,List<Double>>与一个Pair<String,Double>关联起来,其中值是列表中的最小值(或最大值),而键保持不变,然后比较每个Pair<String,Double>以找到具有最低(或最高)值的那个。


2
你正在对包装的Double使用==,这似乎不像预期那样有效。我倾向于尝试远离BinaryOperator<Double>方法,而更喜欢Comparator - Louis Wasserman
没错,但我只需将测试更改为a.equals(b)即可修复它。谢谢你注意到了这一点! - Dici
我真的看不懂这个。也许是语法、缺少成对的文字等原因,但我读 Haskell 时遇到的问题比较少。总的来说,与 Java 中的传统风格相比,函数式编程方法通常要不易读懂得多。 - Michael Piefel
与其他完全设计用于集成函数式编程的语言相比,Java 函数式风格有点啰嗦。您对于 Java 缺少元组语法的观点是正确的,这会使代码更清晰。 - Dici
啊!不要在这里使用 Optional.get,如果 map 为空它会抛出异常。请使用 ifPresent、orElse 或 orElseThrow 等安全方法之一。 - Brian Goetz

4
BinaryOperator不是该任务的好规范,它在缩减中使用以产生适当的值(例如最小或最大),但不适合返回类似于Map键值的相关值。这样使用意味着实现必须执行其他操作以查明BinaryOperator实际上执行了什么,以便在缩减期间选择正确的键值。更糟糕的是,它不能保证BinaryOperator执行允许进行此类缩减的操作,例如运算符可能返回既不是其参数之一的值。

对于这样的任务,Comparator是更好的选择,因为它专门设计用于指定排序并执行相关操作,如查找最大值和最小值。实现可能如下所示:

public static Pair<String,Double> getMinimumKeyValue(
    Map<String, List<Double>> map, Comparator<Double> function) {

    return map.entrySet().stream()
        .map(e->new Pair<>(e.getKey(), e.getValue().stream().min(function).get()))
        .min(Comparator.comparing(Pair::getRight, function)).get();
}

这个函数被命名为getMinimumKeyValue,因为当你传入Comparator.naturalOrder()时它会返回最小的键值对。

但是你也可以通过传入Comparator.reverseOrder()来获取最大值。

而且很容易修改以支持更广泛的用例:

public static <K,V> Pair<K,V> getMinKeyValue(
    Map<K, ? extends Collection<V>> map, Comparator<? super V> function) {

    return map.entrySet().stream()
        .map(e->new Pair<>(e.getKey(), e.getValue().stream().min(function).get()))
        .min(Comparator.comparing(Pair::getRight, function)).get();
}

这仍然适用于从 Map<String, List<Double>> 中获取一个 Pair<String,Double>,但它可以做更多的事情...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接