【问题标题】:Java 8 Strem filter map in map -- Map<String,Map<String,Employee>>地图中的 Java 8 流过滤器地图 -- Map<String,Map<String,Employee>>
【发布时间】:2019-05-24 10:57:33
【问题描述】:

如何使用 Java 8 过滤器过滤 Map&lt;String,Map&lt;String,Employee&gt;&gt;

只有当列表中的任何员工具有字段值 Gender = "M" 时,我才需要过滤。

输入:

Map&lt;String,Map&lt;String,Employee&gt;&gt;

输出:

Map&lt;String,Map&lt;String,Employee&gt;&gt;

过滤条件:

Employee.genter = "M"

如果过滤结果为空,我还必须返回空地图。

我尝试了以下方法,但没有按预期工作。仅当所有员工的性别为“M”时才返回。

tempCollection.entrySet().stream()
                        .filter(i -> i.getValue().entrySet().stream().allMatch(e-> "M".equals(e.getValue().getGender())))
                        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

【问题讨论】:

  • 返回所有性别为M的员工。

标签: java java-8 hashmap java-stream


【解决方案1】:

您可以简单地迭代键值对并过滤为:

Map<String, Map<String, Employee>> output = new HashMap<>();
tempCollection.forEach((k, v) -> {
    if (v.values().stream().anyMatch(i -> "M".equals(i.getGender()))) {
        output.put(k, v.entrySet()
                .stream()
                .filter(i -> "M".equals(i.getValue().getGender()))
                .collect(toMap(Map.Entry::getKey, Map.Entry::getValue)));
    }
});

【讨论】:

  • anyMatch 即使只有一个匹配项也会返回所有结果,如果没有匹配项,我希望删除键值,
  • 如果没有一个员工的性别为“M”,它仍然返回 Map
  • @user1578872 如果过滤结果为空,我必须返回空地图。..这就是你的意思,对吧?
  • 在这种情况下应该是完整的空地图。就像,返回 emptyMap(),而不是 Map
  • 我认为putputIfAbsent 更理想,因为key 总是独一无二的。
【解决方案2】:

函数allMatch 仅在流中的每个元素都与谓词匹配时才匹配;如果有任何元素与谓词匹配,则可以使用anyMatch 进行匹配:

tempCollection.entrySet().stream()
                        .filter(i -> i.getValue().entrySet().stream().anyMatch(e-> "M".equals(e.getValue().getGender())))
                        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

【讨论】:

    【解决方案3】:

    如果有任何员工的性别为“M”,那么您所追求的似乎是Entry&lt;String,Map&lt;String,Employee&gt;&gt;,然后过滤内部Map&lt;String,Employee&gt; 以仅包含性别为“M”的条目。

    在这种情况下,您可以将filteranyMatch 一起作为第一个条件。此外,在收集阶段,您可以在内部地图上应用过滤:

    tempCollection.entrySet().stream()
                .filter(i -> i.getValue().values().stream().anyMatch(e -> "M".equals(e.getGender())))
                .collect(toMap(Map.Entry::getKey,
                        v -> v.getValue().entrySet().stream()
                                .filter(i -> "M".equals(i.getValue().getGender()))
                                .collect(toMap(Map.Entry::getKey, Map.Entry::getValue))));
    

    【讨论】:

    • anyMatch 会返回地图中的所有值,即使只有一名员工的性别为 M。
    • @user1578872 对,感谢接受的答案,我现在可以理解您的要求。 IMO 的描述不是很清楚。无论如何编辑以适应。
    【解决方案4】:

    你可以这样做,

    Map<String, Map<String, Employee>> maleEmpMap = tempCollection.entrySet().stream()
        .map(e -> new AbstractMap.SimpleEntry<>(e.getKey(),
            e.getValue().entrySet().stream().filter(emp -> "M".equals(emp.getValue().getGender()))
                    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))))
        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
    

    从外部映射中获取每个映射条目,并使用相同的键创建一个新的映射条目,并使用相同的键和新构建的嵌套映射创建一个新的映射条目,其中只有男性员工作为它的值。最后将所有匹配的条目收集到一个新的外部映射中。这将优雅地处理您在上面的问题陈述中提到的空场景。

    【讨论】:

      【解决方案5】:

      其他方式是这样的:

      map.values()
           .removeIf(entry->entry.values().stream().anyMatch(e -> !"M".equals(e.getGender())));
      
      map.entrySet()
          .removeIf(entry->entry.getValue().size() == 0);
      

      【讨论】:

        猜你喜欢
        • 2021-09-03
        • 1970-01-01
        • 2019-01-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-04-25
        • 1970-01-01
        相关资源
        最近更新 更多