简体   繁体   English

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

[英]Filtering a stream when given multiple conditions in parameters

I am trying to create a function that takes multiple predicate conditions and filters a stream according to these conditions.我正在尝试创建一个 function ,它采用多个谓词条件并根据这些条件过滤 stream 。 I cannot find anything but my retList just seems to consist of the input rather than a filtered version of the input.我找不到任何东西,但我的 retList 似乎只包含输入而不是输入的过滤版本。

Here are the instructions I was given:以下是我得到的指示:

//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. //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完成每个循环后,将生成的 stream 收集到一个列表中,就像我们在之前的问题中所做的那样,返回结果列表

This is what I have currently:这是我目前拥有的:

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;
}

and this is how it is tested:这就是它的测试方式:

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] 
}

but what I actually get is [5,7,9,11,13,14,21,28,35,42,49,56,63,70,71], the input.但我实际得到的是输入 [5,7,9,11,13,14,21,28,35,42,49,56,63,70,71]。

Try尝试

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]
}

I see here: https://stackoverflow.com/a/51187234/10910098我在这里看到: https://stackoverflow.com/a/51187234/10910098

You could simply create a composite Predicate in your matchAll method and use it to filter the input stream as:您可以简单地在matchAll方法中创建一个复合Predicate并使用它来过滤输入 stream 为:

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());
}

As suggested by Holger , alternatively you can use:正如Holger 所建议的,您也可以使用:

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

In your current implementation, you are not storing the "results" of the filtering anywhere.在您当前的实现中,您不会将过滤的“结果”存储在任何地方。 The filter method does not modify the original stream, which is immutable, but returns a new stream that only contains the matching values from the original stream. filter方法不会修改原来的 stream,它是不可变的,而是返回一个新的 stream,它只包含来自原始 stream 的匹配值。

One way to achieve this is to loop through your conditions, replacing the previous stream with a new one that includes the applied filtering:实现此目的的一种方法是遍历您的条件,将以前的 stream 替换为包含应用过滤的新条件:

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());
}

In your matchAll function, you may consider to change following 2 lines to 1 line.在您的 matchAll function 中,您可以考虑将以下 2 行更改为 1 行。 Check if it works for multiple predicate filter of a data input stream.检查它是否适用于数据输入 stream 的多个谓词过滤器。

Change from从改变

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

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

Change to改成

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

I assume it should give expected output.我认为它应该给出预期的 output。 Hope it helps!希望能帮助到你!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM