在参数中给定多个条件时过滤流

Filtering a stream when given multiple conditions in parameters

我正在尝试创建一个采用多个谓词条件并根据这些条件过滤流的函数。我找不到任何东西,但我的 retList 似乎只包含输入而不是输入的过滤版本。

这是我得到的说明:

//TODO Make a Stream of Integer and set it equal to input for each predicate p on conditions, set this stream variable equals to the result of applying filter(p) to the stream. after completing the for each loop, collect the resulting stream into a List as we have done in previous problems, return the resulting list

这是我目前拥有的:

public static List<Integer> matchAll(Stream<Integer> input,  Predicate<Integer>... conditions) { 
    Stream<Integer> stream = input;
    Stream.of(conditions).peek(p -> stream.filter(p));

    List<Integer> retList = stream.collect(Collectors.toList());

    return retList;
}

这是它的测试方式:

public static void main(String[] args) {
    Stream<Integer> stream = Stream.of(5,7,9,11,13,14,21,28,35,42,49,56,63,70,71);
    Predicate<Integer> p0 = n -> n > 10;
    Predicate<Integer> p1 = n -> n % 2 != 0;
    Predicate<Integer> p2 = n -> isPrime(n);
    System.out.println(Matcher.matchAll(stream, p0, p1, p2));
    // should get [11, 13, 71] 
}

但我实际得到的是[5,7,9,11,13,14,21,28,35,42,49,56,63,70,71],输入

在您当前的实现中,您没有在任何地方存储过滤的 "results"。 filter方法不会修改不可变的原始流,而是returns一个新流,它只包含来自原始流的匹配值。

实现此目的的一种方法是遍历您的条件,用包含已应用过滤的新流替换以前的流:

public static List<Integer> matchAll(Stream<Integer> input,  Predicate<Integer>... conditions) { 
    Stream<Integer> stream = input;
    for (Predicate<Integer> condition : conditions) {
       stream = stream.filter(condition);
    }
    return stream.collect(Collectors.toList());
}

尝试

public static List<Integer> matchAll(List<Integer> input, Predicate<Integer>... conditions) {
    Stream<Integer> streams = input.stream();
    for (Predicate<Integer> predicate : conditions) {
        streams = streams.filter(predicate);
    }
    return streams.collect(Collectors.toList());
}

public static void main(String[] args) {
    List<Integer> list = Arrays.asList(5, 7, 9, 11, 13, 14, 21, 28, 35, 42, 49, 56, 63, 70, 71);
    Predicate<Integer> p0 = n -> n > 10;
    Predicate<Integer> p1 = n -> n % 2 != 0;
    Predicate<Integer> p2 = n -> isPrime(n);
    System.out.println(matchAll(list, p0, p1, p2)); // [11, 13, 71]
}

我看到这里:

在您的 matchAll 函数中,您可以考虑将以下 2 行更改为 1 行。检查它是否适用于数据输入流的多谓词过滤器。

变化自

Stream.of(conditions).peek(p -> stream.filter(p));

List<Integer> retList = stream.collect(Collectors.toList());

改为

List<Integer> retList = stream.filter(t -> Arrays.stream(conditions).allMatch(f -> f.test(t))).collect(Collectors.toList());

我认为它应该给出预期的输出。希望对您有所帮助!

您可以简单地在 matchAll 方法中创建一个复合 Predicate 并使用它来过滤输入流:

public static List<Integer> matchAll(Stream<Integer> input, Predicate<Integer>... conditions) {
    Predicate<Integer> compositePredicate =
        Arrays.stream(conditions).reduce(Predicate::and).orElse(p -> true); // or else filter in all
    return input.filter(compositePredicate).collect(Collectors.toList());
}

作为,或者您可以使用:

return Arrays.stream(conditions)
             .reduce(Predicate::and)
             .map(input::filter) // Optional.map here
             .orElse(input)
             .collect(Collectors.toList()); // terminal operation