2

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.

3
  • 1
    In your code, p is a Set<Item>. anyMatch() means that if there are any in the entire set that are false, the whole set gets included. Commented Feb 9, 2018 at 4:11
  • oh I don't want that at all.. So, what I want is to have any those Items in the Set 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. Status is a boolean. Let me update the question to include these details. Commented Feb 9, 2018 at 4:21
  • Thanks Silas. From p, how do I filter out all the Items as per the condition while retaining the Set? I will update question with what I tried to do. Commented Feb 9, 2018 at 4:30

4 Answers 4

3
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())
            ));
}
Sign up to request clarification or add additional context in comments.

1 Comment

.filter(item -> !Boolean.TRUE.equals(item.status))
2

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());

Comments

0

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.

Comments

0

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()))
            );
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.