经过数小时的研究,我找不到解决问题的方法。我有一个Map<String, List<User>>,我想根据列表中的某些值删除地图上的某些项目。
我必须跟随User类
public class User {
public String firstName,
public Integer age
public boolean is50() {
return this.age.equals(50);
}
}
Run Code Online (Sandbox Code Playgroud)
我有一个这样的地图:
Map<String, List<User> myMap = new HashMap<>();
myMap.put("A", new ArrayList<>());
myMap.get("A").add(new User("John", 50));
myMap.get("A").add(new User("Bob", 30));
myMap.put("B", new ArrayList<>());
myMap.get("B").add(new User("Sam", 25));
myMap.get("B").add(new User("Sarah", 56));
myMap.put("C", new ArrayList<>());
myMap.get("C").add(new User("Gill", 15));
myMap.get("C").add(new User("Jim", 20));
Run Code Online (Sandbox Code Playgroud)
现在,如果列表年龄中至少有一个用户为50,我想删除Map的条目。而且,我想使用Java 8功能来实现这一点。
我发现有一个removeIf功能,但不能使其与列表一起使用。
我已经尝试过这样的事情:
Map<String, List<User> filteredMap = myMap
.enrySet()
.removeIf(e -> e.getValue()
.stream()
.filter(user -> user::is50)
.collect(Collectors.toList())
Run Code Online (Sandbox Code Playgroud)
当然那是行不通的:(
例外的输出是一个过滤的地图,所有用户只有B和C键(必须删除A键,因为John有50岁了)
谢谢您的帮助,希望一切都清楚;)
这应该可以解决问题:
myMap.entrySet()
.removeIf(e -> e.getValue()
.stream()
.anyMatch(User::is50));
Run Code Online (Sandbox Code Playgroud)
请注意,entrySet()修改(removeIf)会影响条目集支持的映射。因此,您必须制作地图的副本并在副本上运行它,或者myMap修改第一个地图()。
至于制作地图副本,您只需执行以下操作:
Map<String, List<User>> copy = new HashMap<>(myMap);
Run Code Online (Sandbox Code Playgroud)
编辑:
根据@Holger的建议,执行就地删除的更好方法如下:
myMap.values()
.removeIf(v -> v.stream()
.anyMatch(User::is50));
Run Code Online (Sandbox Code Playgroud)
更好的原因有四个:
getValue因为values直接提供了设置的值。values与值之间的逻辑飞跃比entrySet与值之间的逻辑飞跃少。peek,尽管有时更简洁,但使用调试外部是反模式)。values是由地图的支持。只需将其Stream::noneMatch用于嵌套Stream:
Map<String, List<User>> filteredMap = myMap.entrySet()
.stream()
.filter(e -> e.getValue()
.stream()
.noneMatch(User::is50)
)
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
filteredMap.forEach((key, value) -> System.out.println(key));
Run Code Online (Sandbox Code Playgroud)
输出为:
B
C
Run Code Online (Sandbox Code Playgroud)
myMap自从我stream用完entrySet之后再收集它,在此解决方案中将不受影响。Set::removeIf由于Map::entrySet返回Set的条目支持您的原始地图,因此会更改您以前的地图Map。