Java 8 - 使用BiPredicate进行过滤

时间:2016-03-15 19:46:36

标签: java lambda filter functional-programming predicate

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

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

但是过滤方法没有收到BiPredicate。为什么不?有什么替代方案?

4 个答案:

答案 0 :(得分:10)

您仍然可以使用Bipredicate。 filter-method需要的参数是Predicate,所以这里是一个如何使用这个BiPredicate的例子:

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

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

在此示例中,flavoursPrices必须是List。

我们正在使用的lambda:

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

正在用BiPredicate替换匿名内部类声明来创建一个新谓词:

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

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

答案 1 :(得分:3)

由于filter不起作用,因此它一次只过滤一个集合。对于你的任务,你需要像Python的itertools.product;这可以使用flatMap来实现。在Scala中,这看起来很短:

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是最强大的功能之一;几乎所有的流转换(过滤器,地图,笛卡尔积,扁平化)都可以用它来实现。休息(如拉链)几乎总是折叠/减少(或很少,展开)。

答案 2 :(得分:3)

使用StreamEx library

实现解决方案的方式
StreamEx.ofPairs(prices, (p1, p2) -> p1 + p2 == 5 ? StreamEx.of(p1, p2) : StreamEx.empty())
            .flatMap(Function.identity())
            .forEach(price -> System.out.println(price));

您可能还想创建自己的类来封装对。

答案 3 :(得分:2)

Predicate!= BiPredicate

Stream#filter需要Predicate (Object -> boolean)一次处理每个元素。

您可能需要查看StreamEx库以获取解决方案。

它有方法将流中的连续元素配对。

StreamEx