问题
How to filter a Map<String,Map<String,Employee>>
using Java 8 Filter?
I have to filter only when any of employee in the list having a field value Gender = "M".
Input:
Map<String,Map<String,Employee>>
Output:
Map<String,Map<String,Employee>>
Filter criteria:
Employee.genter = "M"
Also i have to return empty map if the filtered result is empty.
I tried the below, but it is not working as expected. It is returning the only if all the Employees are with gender "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));
回答1:
You could simply iterate on the key-value pairs and filter as:
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)));
}
});
回答2:
The function allMatch
only matches if every element in the stream matches the predicate; you can use anyMatch
to match if any element matches the predicate:
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:
Seems like what you're after is given a Entry<String,Map<String,Employee>>
if there's any employee who has a gender of "M" then filter the inner Map<String,Employee>
to contain only entries with a gender "M".
in which case you can filter
along with anyMatch
for the first criterion. Further, at the collecting phase, you can then apply the filtering on the inner map:
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))));
回答4:
You may do it like so,
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));
Take each map entry from the outer map and create a new map entry using the same key and the newly constructed nested map with the same key and which has only male employees as it's value. Finally collect all those matching entries into a new outer map. This will gracefully handle the empty scenario which you mentioned in the problem statement above.
回答5:
Other way would be like this:
map.values()
.removeIf(entry->entry.values().stream().anyMatch(e -> !"M".equals(e.getGender())));
map.entrySet()
.removeIf(entry->entry.getValue().size() == 0);
来源:https://stackoverflow.com/questions/53927656/java-8-strem-filter-map-in-map-mapstring-mapstring-employee