地图中的 Java 8 流过滤器地图 -- Map<String,Map<String,Employee>>

Posted

技术标签:

【中文标题】地图中的 Java 8 流过滤器地图 -- Map<String,Map<String,Employee>>【英文标题】:Java 8 Strem filter map in map -- 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的员工。 【参考方案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);

【讨论】:

以上是关于地图中的 Java 8 流过滤器地图 -- Map<String,Map<String,Employee>>的主要内容,如果未能解决你的问题,请参考以下文章

在java 8中将地图映射转换为单个值列表[关闭]

Java 8,流过滤器,反射,NoSuchMethodException [重复]

Python fluent过滤器、地图等

Java 8,流过滤器,反射,NoSuchMethodException [重复]

Java 8 地图合并方法

根据另一个地图中的值对Java Map进行排序