Java 8 - 使用 BiPredicate 进行筛选

我有一个整数流,我想找到两个总和等于另一个数字的数字。所以我想出了以下解决方案:

BiPredicate<Integer, Integer> p = (price1, price2) -> price1.intValue() + price2.intValue() == moneyQty;
flavoursPrices.filter(p);

但筛选方法不会收到双向谓词。为什么不呢?有什么替代方案呢?


答案 1

您仍然可以使用 Bipredicate。filter-method 需要的参数是谓词,因此下面是一个如何使用此 BiPredicate 的示例:

 BiPredicate<Integer, Integer> p = (price1, price2) -> price1.intValue() + price2.intValue() == moneyQty;

flavoursPrices.stream().filter(el->p.test(el.price1,el.price2));

在此示例中,口味价格必须是列表。

我们正在使用的 lambda:

el->p.test(el.price1,el.price2)

正在替换匿名内部类声明,以便从 Bi 谓词中创建新的谓词:

 Predicate<Integer> arg =new Predicate<Integer>() {
        @Override
        public boolean test(Element el) {
            return p.test(el.price1,el.price2);
        }
    };

因此,为了过滤流,我们正在为来自流的每个元素创建一个新的谓词,然后使用此谓词作为参数来使用它的测试方法。这样做的最大优点是,我们不必提前创建大量的谓词,但是我们可以传递lambda函数中的每个元素并获取它的属性。


答案 2

因为不是以这种方式工作的,所以它一次只筛选一个集合。对于你的任务,你需要像Python这样的东西;这可以使用 来实现。在Scala中,这看起来很短:filteritertools.productflatMap

prices.flatMap(p1 => 
  prices.flatMap(p2 => 
    if (p1 + p2 == 5) List((p1, p2)) else List()))

如果你想在(原生)Java中做到这一点,就会出现这样的事情:

import java.util.*;
import java.util.stream.*;

public class Main {

    public static void main(String[] args) {

        List<Integer> prices =  Arrays.asList(1,2,3,4,5,6,7,8,9);

        List<List<Integer>> result = prices.stream().flatMap(p1 ->
            prices.stream().flatMap(p2 ->
                p1 + p2 == 5 ? Stream.of(Arrays.asList(p1, p2)) : Stream.empty()
            )
        ).collect(Collectors.toList());

        System.out.println(result);

    }
}

...它打印 .但我不会在现实中使用它;)至少,元组类会很好。[[1, 4], [2, 3], [3, 2], [4, 1]]

值得注意的是,最强大的功能之一是;几乎所有的流变换(过滤器,映射,笛卡尔积,扁平化)都可以使用它来实现。休息(如拉链)几乎总是折叠/减少(或者,很少,展开)。flatMap