对 Java 中的地图应用多个过滤器
Apply multiple filter to a map in Java
基于以下问题:
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));
}
此过滤器在 dehli
中离开的学生。我如何过滤 dehli
、amsterdam
或 new york
中离开的学生?
有没有比过滤三倍原始地图并将三个输出合并在一起更好的方法?
在多个条件下使用一个过滤器:
public void filterStudents(Map<Integer, Student> studentsMap){
Map<Integer, Student> filteredStudentsMap =
studentsMap.entrySet()
.stream()
.filter(s -> s.getValue().getAddress().equalsIgnoreCase("delhi") ||
s.getValue().getAddress().equalsIgnoreCase("amsterdam") ||
s.getValue().getAddress().equalsIgnoreCase("new york"))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}
或者您可以使用 Set
进行简化:
public void filterStudents(Map<Integer, Student> studentsMap){
Map<Integer, Student> filteredStudentsMap =
studentsMap.entrySet()
.stream()
.filter(s -> Set.of("delhi","amsterdam","new york").contains(s.getValue().getAddress().toLowerCase()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}
有Predicate#or(Predicate)
逻辑组合两个Predicate
。
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);
一个 filter
调用看起来像
.filter(e -> livesInAnyOfTheseThreeCities.test(e.getValue()))
How could I adapt the fourth lines where you're chaining filtering parameters?
假设我们有一系列城市
final String[] cities = {"delhi", "amsterdam", "new york"};
对于每个 Student
,我们可以写一个 Predicate<Student>
并将它们减少 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
在没有给出城市时使用。
List<String> toFilter = Arrays.asList("delhi", "amsterdam", "new york");
Map<Integer, Student> filteredStudentsMap =
studentsMap.entrySet()
.stream()
.filter(s -> toFilter.stream().anyMatch(f -> s.getValue().getAddress().equalsIgnoreCase(f)))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
当然,您应该在这里使用普通的旧式面向对象编程,并创建一个名称有意义的单独方法:
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));
}
当然这需要在Student
class中创建相应的方法,但为什么我们还需要对象和OOP?)
public class Student {
// other methods of Student
public boolean liveIn(String... cities) {
return Arrays.stream(cities).anyMatch(this.city::equals);
}
}
Array 只是一个例子——您可以使用 set、list 或任何您想要的。
这里的重点是创建一个可以在流 api 中使用的有意义的方法。
你也可以试试这个,如果你不确定,在不久的将来有多少城市可以进入过滤条件..
public void filterStudents(Map<Integer, Student> studentsMap){
final List<String> includedCities = List.of("DELHI", "NEW YORK", "AMSTERDEM", "SOME MORE");
Map<Integer, Student> filteredStudentsMap =
studentsMap.entrySet()
.stream()
.filter(s -> includedCities.contains(s.toUpperCase()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}
更新(@JoachimSauer 发表评论后):
这个应该好很多..
public void filterStudents(Map<Integer, Student> studentsMap){
final List<String> includedCities = List.of("DELHI", "NEW YORK", "AMSTERDEM", "SOME MORE");
Map<Integer, Student> filteredStudentsMap =
studentsMap.entrySet()
.stream()
.filter(s -> exclusiveCities.stream().anyMatch(s::equalsIgnoreCase))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}
更新(@Holger 发表评论后):
更好..
public void filterStudents(Map<Integer, Student> studentsMap){
final Set<String> includedCities = new TreeSet<>(CASE_INSENSITIVE_ORDER);
Collections.addAll( includedCities , "DELHI", "NEW YORK", "AMSTERDEM", "SOME MORE");
Map<Integer, Student> filteredStudentsMap =
studentsMap.entrySet()
.stream()
.filter(includedCities::contains))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}
基于以下问题:
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));
}
此过滤器在 dehli
中离开的学生。我如何过滤 dehli
、amsterdam
或 new york
中离开的学生?
有没有比过滤三倍原始地图并将三个输出合并在一起更好的方法?
在多个条件下使用一个过滤器:
public void filterStudents(Map<Integer, Student> studentsMap){
Map<Integer, Student> filteredStudentsMap =
studentsMap.entrySet()
.stream()
.filter(s -> s.getValue().getAddress().equalsIgnoreCase("delhi") ||
s.getValue().getAddress().equalsIgnoreCase("amsterdam") ||
s.getValue().getAddress().equalsIgnoreCase("new york"))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}
或者您可以使用 Set
进行简化:
public void filterStudents(Map<Integer, Student> studentsMap){
Map<Integer, Student> filteredStudentsMap =
studentsMap.entrySet()
.stream()
.filter(s -> Set.of("delhi","amsterdam","new york").contains(s.getValue().getAddress().toLowerCase()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}
有Predicate#or(Predicate)
逻辑组合两个Predicate
。
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);
一个 filter
调用看起来像
.filter(e -> livesInAnyOfTheseThreeCities.test(e.getValue()))
How could I adapt the fourth lines where you're chaining filtering parameters?
假设我们有一系列城市
final String[] cities = {"delhi", "amsterdam", "new york"};
对于每个 Student
,我们可以写一个 Predicate<Student>
并将它们减少 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
在没有给出城市时使用。
List<String> toFilter = Arrays.asList("delhi", "amsterdam", "new york");
Map<Integer, Student> filteredStudentsMap =
studentsMap.entrySet()
.stream()
.filter(s -> toFilter.stream().anyMatch(f -> s.getValue().getAddress().equalsIgnoreCase(f)))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
当然,您应该在这里使用普通的旧式面向对象编程,并创建一个名称有意义的单独方法:
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));
}
当然这需要在Student
class中创建相应的方法,但为什么我们还需要对象和OOP?)
public class Student {
// other methods of Student
public boolean liveIn(String... cities) {
return Arrays.stream(cities).anyMatch(this.city::equals);
}
}
Array 只是一个例子——您可以使用 set、list 或任何您想要的。 这里的重点是创建一个可以在流 api 中使用的有意义的方法。
你也可以试试这个,如果你不确定,在不久的将来有多少城市可以进入过滤条件..
public void filterStudents(Map<Integer, Student> studentsMap){
final List<String> includedCities = List.of("DELHI", "NEW YORK", "AMSTERDEM", "SOME MORE");
Map<Integer, Student> filteredStudentsMap =
studentsMap.entrySet()
.stream()
.filter(s -> includedCities.contains(s.toUpperCase()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}
更新(@JoachimSauer 发表评论后):
这个应该好很多..
public void filterStudents(Map<Integer, Student> studentsMap){
final List<String> includedCities = List.of("DELHI", "NEW YORK", "AMSTERDEM", "SOME MORE");
Map<Integer, Student> filteredStudentsMap =
studentsMap.entrySet()
.stream()
.filter(s -> exclusiveCities.stream().anyMatch(s::equalsIgnoreCase))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}
更新(@Holger 发表评论后):
更好..
public void filterStudents(Map<Integer, Student> studentsMap){
final Set<String> includedCities = new TreeSet<>(CASE_INSENSITIVE_ORDER);
Collections.addAll( includedCities , "DELHI", "NEW YORK", "AMSTERDEM", "SOME MORE");
Map<Integer, Student> filteredStudentsMap =
studentsMap.entrySet()
.stream()
.filter(includedCities::contains))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}