Based on the following question: filter Map in Java 8 Streams
public void filterStudents(Map<Integer, Student> studentsMap){
Map<Integer, Student> filteredStudentsMap =
studentsMap.entrySet()
.stream()
.filter(s -> s.getValue().getAddress().equalsIgnoreCase("delhi"))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}
This filter students leaving in dehli. How could I filter students leaving in dehli, amsterdam or new york?
Is there a better way than filtering three times the original map and merging the three outputs together?
There is Predicate#or(Predicate) to logically compose two Predicates.
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.
Of course, you should use plain old object oriented programming here and create a separate method with meaningful name:
public void filterStudents(Map<Integer, Student> studentsMap){
Map<Integer, Student> filteredStudentsMap =
studentsMap.entrySet()
.stream()
.filter(s -> s.getValue().liveIn("delhi", "amsterdam", "new york"))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}
Of course this requires creating a corresponding method in Student class, but why else do we need objects and OOP?)
public class Student {
// other methods of Student
public boolean liveIn(String... cities) {
return Arrays.stream(cities).anyMatch(this.city::equals);
}
}
Array is just for example - you can use set, list or whatever you want. The point here is to create a meaningful methods that could be used in stream api.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With