【问题标题】:How to compare two lists of double values using lambda expressions如何使用 lambda 表达式比较两个双精度值列表
【发布时间】:2018-03-30 04:24:51
【问题描述】:

让我们从以下列表开始:

List<Double> firstList = new ArrayList<>();
firstList.add(2.0);
firstList.add(3.0);
List<Double> secondList = new ArrayList<>();
secondList .add(2.0000000001);
secondList .add(2.99999999994);

我知道我可以使用蛮力一一比较每个元素。当然,我已经检查过两个列表的元素数量是否相同。

boolean isEqual = true;
for (int i = 0; i < firstList.size(); i++) {
  isEqual &= Math.abs(firstList.get(i) - secondList.get(i)) < 1.0e-6;
}
return isEqual;

我的问题:有没有办法使用 lambda 表达式比较这两个双精度值列表?使用任何其他类型的对象似乎都很容易,但对于双打则不然。我需要检查这两个列表在数值上是否相等。

提前致谢。

【问题讨论】:

标签: java lambda comparison


【解决方案1】:

鉴于声明:

当然,我已经检查了两个列表的数量相同 元素。

然后您可以使用IntStream.rangeallMatch 完成相同的结果,如下所示:

boolean isEqual =  firstList.isEmpty() || 
         IntStream.range(0, firstList.size())
           .allMatch(i -> Math.abs(firstList.get(i) - secondList.get(i)) < 1.0e-6);

使用reduce的另一种解决方案:

BiPredicate<Double, Double> biPredicate = (e, a) -> Math.abs(e - a) < 1.0e-6;
boolean isEqual = 
         IntStream.range(0, firstList.size())
                  .boxed()
                  .reduce(Boolean.TRUE,
                    (accumulator, i) -> Boolean.logicalAnd(accumulator, biPredicate.test(firstList.get(i), secondList.get(i))),
                    (a, b) -> {
                        throw new RuntimeException("not implemented");
                    });

我故意将第三个参数(组合器)留给reduce 未实现,因为它根本不会被调用。原因是这个特定的重载被设计为与并行流一起使用,因此为了使组合器工作,流必须是并行的。

然而,我们仍然需要使用这个重载来完成手头的任务。

【讨论】:

  • 我不明白为什么你必须使用组合字段。你不能只用T reduce(T identity, BinaryOperator&lt;T&gt; accumulator);吗?
  • @MichałZabielski 该重载声明identity 以及accumulator 的参数必须全部为同一类型。如果我继续采用这种方法,代码将无法编译。因此需要这种重载,它允许identity 是与流中的元素不同的类型。在这种情况下,accumulator 的类型为 Booleani 的类型为 Integer。这使我能够折叠成布尔结果以及访问索引。
  • @MichałZabielski 查看重载 you've suggested 和重载 I am using 的签名。
  • 好的,现在我明白了。实际上,您在 reduce 中执行了两个步骤:比较两个列表中的 double,然后将其减少为一个布尔值。很高兴通过combiner 字段了解这项技术:)
  • 我永远不会使用第二种方法。它不仅更长,而且不短路。如果一对元素不满足条件,为什么要一直检查到最后一个?
【解决方案2】:

在函数式语言中,您可以使用 zip 函数压缩两个列表(流),然后使用 map 或 reduce 使用 lambda 操作合并列表。不幸的是,Java 没有这种开箱即用的功能。但是,您可以使用 Google Guava Streams 压缩两个列表并使用 lambda(函数式)获取结果:

    BiFunction<Double, Double, Boolean> zippingFunction = (a, b) -> Math.abs(a - b) < 1.0e-6;

    boolean result = Streams.zip(firstList.stream(), secondList.stream(), zippingFunction)
            .reduce(true, Boolean::logicalAnd);

【讨论】:

  • 不错!您可以在没有外部库的情况下实现相同的目标,尽管它可能不那么整洁。我已经在我的帖子中提供了它:)
【解决方案3】:

当然。使用接受两个 List 并返回布尔值的比较方法创建一个接口。将现有代码包装在 lambda 表达式中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-11
    • 1970-01-01
    • 2020-02-08
    相关资源
    最近更新 更多