How to apply multiple predicates to a java.util.Stream?
I am assuming your Filter
is a type distinct from java.util.function.Predicate
, which means it needs to be adapted to it. One approach which will work goes like this:
things.stream().filter(t -> filtersCollection.stream().anyMatch(f -> f.test(t)));
This incurs a slight performance hit of recreating the filter stream for each predicate evaluation. To avoid that you could wrap each filter into a Predicate
and compose them:
things.stream().filter(filtersCollection.stream().<Predicate>map(f -> f::test)
.reduce(Predicate::or).orElse(t->false));
However, since now each filter is behind its own Predicate
, introducing one more level of indirection, it is not clear-cut which approach would have better overall performance.
Without the adapting concern (if your Filter
happens to be a Predicate
) the problem statement becomes much simpler and the second approach clearly wins out:
things.stream().filter(
filtersCollection.stream().reduce(Predicate::or).orElse(t->true)
);
Java Stream filter match multiple criteria predicate
Try this out,
List<Person> filteredPeople = persons.stream()
.filter(p -> p.getAge() > 30)
.filter(p -> p.getAge() < 32)
.filter(p -> p.getHasComputer())
.limit(5).collect(Collectors.toList());
Notice that you may add additional filter
predicates as needed. This is just a template to get your work done.
Or else if you have some dynamic number of Predicates
passed by some external client you can still do it like so.
Predicate<Person> ageLowerBoundPredicate = p -> p.getAge() > 30;
Predicate<Person> ageUpperBoundPredicate = p -> p.getAge() < 32;
Predicate<Person> hasComputerPred = p -> p.getHasComputer();
List<Predicate<Person>> predicates = Arrays.asList(ageLowerBoundPredicate, ageUpperBoundPredicate,
hasComputerPred);
List<Person> filteredPeople = persons.stream()
.filter(p -> predicates.stream().allMatch(f -> f.test(p)))
.limit(5).collect(Collectors.toList());
Java Streams: Find first for multiple filter predicates
How about doing it the other way around? Streaming the products, and applying predicates on them.
List<Predicate<Product>> predicates = getPredicates();
List<Product> products = getProducts();
List<Product> filtered = products.stream().filter(product -> {
Iterator<Predicate<Product>> iterator = predicates.iterator();
while (iterator.hasNext()) {
Predicate<Product> currentPredicate = iterator.next();
if (currentPredicate.test(product)) {
iterator.remove();
return true;
}
}
return false;
}).collect(Collectors.toList());
The downside is you have to be careful which collection you use for predicates, Iterator.remove
is not always supported.
Edit: Looks like i wasn't reading carefully enough. I think getting one of each would be best with loop.
List<Product> products = getProducts();
List<Predicate<Product>> predicates = getPredicates();
List<Product> matchingProducts = new ArrayList<>(predicates.size());
for (Product product : products) {
if (predicates.isEmpty()) {
break;
}
for (int predicateIndex = 0; predicateIndex < predicates.size(); predicateIndex++) {
Predicate<Product> predicate = predicates.get(predicateIndex);
if (predicate.test(product)) {
matchingProducts.add(product);
predicates.remove(predicateIndex);
break;
}
}
}
Actually managed to achieve it with a stream and takeWhile
, you were correct, Benjamin.
List<Predicate<Product>> predicates = getPredicates();
List<Product> products = getProducts();
List<Product> matches = products.stream()
.takeWhile(product -> !predicates.isEmpty())
.filter(product -> {
Iterator<Predicate<Product>> iterator = predicates.iterator();
while (iterator.hasNext()) {
if (iterator.next().test(product)) {
iterator.remove();
return true;
}
}
return false;
})
.collect(Collectors.toList());
Just make sure takeWhile
is before filter
, otherwise last matching element gets skipped.
How to combine all predicates from ListPredicateMyClass
You can stream and reduce
them like this:
Predicate<TaskFx> predicate = predicates.stream()
.reduce(x -> true, Predicate::and);
Apply multiple filter to a map in Java
There is Predicate#or(Predicate)
to logically compose two Predicate
s.
Predicate<Student> livesInDelhi = student -> "delhi".equalsIgnoreCase(student.getAddress());
Predicate<Student> livesInAmsterdam = student -> "amsterdam".equalsIgnoreCase(student.getAddress());
Predicate<Student> livesInNewYork = student -> "new york".equalsIgnoreCase(student.getAddress());
Predicate<Student> livesInAnyOfTheseThreeCities = livesInDelhi.or(livesInAmsterdam).or(livesInNewYork);
A filter
call would look like
.filter(e -> livesInAnyOfTheseThreeCities.test(e.getValue()))
How could I adapt the fourth lines where you're chaining filtering parameters?
Assuming we have an array of cities
final String[] cities = {"delhi", "amsterdam", "new york"};
for each Student
, we could write a Predicate<Student>
and reduce them by Predicate::or
Predicate<Student> livesInAnyOfGivenCities =
Arrays.stream(cities)
.map(city -> (Predicate<Student>) student -> city.equalsIgnoreCase(student.getAddress()))
.reduce(Predicate::or)
.orElseGet(() -> student -> false);
student -> false
is used when there are no cities given.
How to apply multiple Filters on Java Stream?
I suppose you want to keep all the TestObjects
that satisfy all the conditions specified by the map?
This will do the job:
List<TestObject> newList = list.stream()
.filter(x ->
filterMap.entrySet().stream()
.allMatch(y ->
x.getProperty(y.getKey()) == y.getValue()
)
)
.collect(Collectors.toList());
Translated into "English",
filter
the listlist
by keeping all the elementsx
that:
- all of the key value pairs
y
offilterMap
must satisfy:
x.getProperty(y.getKey()) == y.getValue()
(I don't think I did a good job at making this human readable...) If you want a more readable solution, I recommend Jeroen Steenbeeke's answer.
Java 8 Streams - Filter More Than One Condition
Simple enough
resultList.stream()
.filter(fixture -> fixture.getHome().equals(team) || fixture.getAway().equals(team)))
.collect(toList());
EDIT: This is on the assumption that order does not matter to you. If your final list needs to have home result and then away, have a look at Elliott Frisch's answer.
Apply few Predicates to stream filter in groovy
Predicate<SystemRunlife> filter = { systemRl -> true }
for (Predicate<SystemRunlife> systemRunlifePredicate : filterCollection) {
filter = (filter & systemRunlifePredicate)
}
I had combined predicates that way. Maybe someone can propose more convineint way.
How to use stream to apply multiple filters and convert to a List
For the next question, please provide real code instead of incomplete, typo ridden pseudo code.
As you need the complete list of A
s for step 3, you have to collect any potential stream from step 2 into a list anyway. Step 2 and 4 can be simplified by using streams, though:
public static List<A> makeListfromGroup(Map<Object, List<A>> m, Predicate<A> condition)
{
return m.values()
.stream()
.map(as -> as.stream().filter(condition).findAny().orElse(null))
.filter(Objects::nonNull)
.collect(Collectors.toList());
}
For step 4, you can read how to apply multiple conditions at once here:
public static List<B> applyFilter(List<B> list, List<Predicate<B1>> filtreB1, List<Predicate<B2>> filtreB2)
{
return list.stream()
.filter(b -> filtreB1.stream().allMatch(p -> p.test(b.getB1())))
.filter(b -> filtreB2.stream().allMatch(p -> p.test(b.getB2())))
.collect(Collectors.toList());
}
Related Topics
How to Display Bar Value on Top of Bar Javafx
Using Spring Resttemplate in Generic Method with Generic Parameter
Drag and Drop Custom Object from Jlist into Jlabel
Copy Entire Directory Contents to Another Directory
Printing a Large Swing Component
Detect If Java Application Was Run as a Windows Admin
Closing a Joptionpane Programmatically
Howto Extract Mimetype from a Byte[]
In Java How to Re-Open System.In After Closing It
How to Create a Delay in Swing
Jbutton() Only Working When Mouse Hovers
How to Programmatically Inject a Java Cdi Managed Bean into a Local Variable in a (Static) Method
How to Set Color to a Certain Row If Certain Conditions Are Met Using Java