删除Map <Long,List <Object >>的条目

Pie*_*nes 5 java java-stream

经过数小时的研究,我找不到解决问题的方法。我有一个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岁了)

谢谢您的帮助,希望一切都清楚;)

Avi*_*Avi 8

这应该可以解决问题:

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)

更好的原因有四个:

  1. 您可以取消对的调用,getValue因为values直接提供了设置的值。
  2. 它可以更清晰地传达意图- values与值之间的逻辑飞跃比entrySet与值之间的逻辑飞跃少。
  3. 它更简洁,而且不是反模式(例如peek,尽管有时更简洁,但使用调试外部是反模式)。
  4. 它仍然有效,因为收藏返回由values由地图的支持


mic*_*alk 7

只需将其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

  • 如果其中任何一个回答您的问题,@ PierreJones会考虑接受其中一个答案。 (2认同)