Reputation: 303
This is class Item.
public class Item {
String id;
String name;
Integer value;
Boolean status;
}
I have a Map(String, Set(Item)). I want to write a method that returns a Map(String, Set(Item)) such that only Items with status = false or status = null are present in the resulting map. I don't want a set-wide operation. I want the resulting subsets to only contain those Item that have status == Boolean.FALSE OR status == null. I don't want the entire set to get included or excluded. I only want those individual items included or excluded as per the status value.
Here's what I've tried so far.
public Map<String,Set<Item>> filterByStatus(Map<String, Set<Item>> changes) {
return changes.entrySet()
.stream()
.filter(p -> p.getValue()
.stream()
.anyMatch(item -> BooleanUtils.isNotTrue(item.isStatus())))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}
It didn't work! I get back the same results as I would if I didn't call filterByStatus.
UPDATE
public Map<String,Set<Item>> filterByStatus(Map<String, Set<Item>> changes) {
return changes.entrySet()
.stream()
.map(p -> p.getValue()
.stream()
.filter(item -> BooleanUtils.isNotTrue(item.isStatus())))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}
Result: There's an error in the collect(Collectors.toMap()) line saying Non-static method cannot be referenced from static context.
Upvotes: 2
Views: 1510
Reputation: 298153
Alternatively to a Stream solution, you may use
public Map<String, Set<Item>> filterByStatus(Map<String, Set<Item>> changes) {
Map<String, Set<Item>> result = new HashMap<>(changes);
result.replaceAll((key, set) -> {
set = new HashSet<>(set);
set.removeIf(item -> Boolean.TRUE.equals(item.status));
return set;
});
// if you want to remove empty sets afterwards:
result.values().removeIf(Set::isEmpty);
return result;
}
You could even do the operation in-place if the sets are mutable and you don’t need the old state anymore:
changes.values().forEach(set -> set.removeIf(item -> Boolean.TRUE.equals(item.status)));
// if you want to remove empty sets afterwards (and the map is mutable):
changes.values().removeIf(Set::isEmpty);
you could even remove these items, followed by removing the set only if they became empty due to the removal, in one statement:
changes.values().removeIf(set ->
set.removeIf(item -> Boolean.TRUE.equals(item.status)) && set.isEmpty());
Upvotes: 2
Reputation: 1948
This avoid include in new Map entrys with 0 items.
private Map<String,Set<Item>> filterByStatus(Map<String, Set<Item>> changes) {
return changes.entrySet()
.stream()
.filter(entry -> entry.getValue()
.stream()
.anyMatch(item -> item.status == null || item.status == false))
.collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue()
.stream()
.filter(item -> item.status == null || item.status == false)
.collect(Collectors.toSet()))
);
}
Upvotes: 0
Reputation: 31813
public Map<String, Set<Item>> filterByStatus(Map<String, Set<Item>> changes) {
return changes.entrySet()
.stream()
.collect(Collectors.toMap(Map.Entry::getKey, entry ->
entry.getValue()
.stream()
.filter(item -> item.status == null || item.status == Boolean.FALSE)
.collect(Collectors.toSet())
));
}
Upvotes: 3
Reputation: 16494
Judging from your description you are looking for allMatch
rather than anyMatch
.
Currently you get all the sets which contain at least one non-True value. What you seem to want is having only sets that consist of non-True values only.
If you are rather looking for filtering out the negative values from all sets, you should use a mapping, not just filter, on the Map. In the mapping you could create copies of the sets with True values excluded.
Upvotes: 0