Reputation: 79
I am trying to create a function that takes multiple predicate conditions and filters a stream according to these conditions. I cannot find anything but my retList just seems to consist of the input rather than a filtered version of the input.
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. after completing the for each loop, collect the resulting stream into a List as we have done in previous problems, return the resulting list
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.
Upvotes: 1
Views: 2571
Reputation: 1319
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.
One way to achieve this is to loop through your conditions, replacing the previous stream with a new one that includes the applied filtering:
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());
}
Upvotes: 1
Reputation: 31878
You could simply create a composite Predicate
in your matchAll
method and use it to filter the input stream as:
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:
return Arrays.stream(conditions)
.reduce(Predicate::and)
.map(input::filter) // Optional.map here
.orElse(input)
.collect(Collectors.toList()); // terminal operation
Upvotes: 3
Reputation: 1129
In your matchAll function, you may consider to change following 2 lines to 1 line. Check if it works for multiple predicate filter of a data input 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. Hope it helps!
Upvotes: 1
Reputation: 747
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
Upvotes: 3