Skip to content

Filter and collect a Map<String, List> to Map<String, List> based on a condition

Let

class Person {
    String name;
    int age;
}

My variable is

Map<Sring, List<Person>> myVariable;

The result I’m aiming to get is

Map<String, List<Person>> result;

The condition is to collect all persons satisfying this condition

Predicate<Person> predicate = p -> p.age > 20;

If an entry in the map contains 3 persons and only 2 of them satisfies this condition, the 3rd one should be removed

Example: myVariable =

"1": [{name: "Foo", age: 15}, {name: "Foo", age: 13}, {name: "Foo", age: 14}]
"2": [{name: "Foo", age: 15}, {name: "Foo", age: 13}, {name: "Foo", age: 14}]
"3": [{name: "Foo", age: 15}, {name: "Foo", age: 13}, {name: "Foo", age: 14}]
"4": [{name: "Foo", age: 15}, {name: "Foo", age: 21}, {name: "Foo", age: 27}]

result =

"4": {name: "Foo", age: 21}, {name: "Foo", age: 27}]

I tried this

Map<String, List<Persin>> result = myVariable.keySet().stream()
            .filter(p -> myVariable.keySet(p).stream().anyMatch(predicate))
            .collect(Collectors.toMap(p -> p, myVariable.get(Function.identity()).stream().filter(predicate).collect(Collectors.toList())));

But it doesn’t work.

Answer

You can use two filter calls:

Map<String, List<Person>> result = myVariable.entrySet().stream()
        .map(entry -> Map.entry(entry.getKey(), entry.getValue()
                .stream().filter(p -> p.getAge() > 20)
                .collect(Collectors.toList())))
        .filter(entry -> !entry.getValue().isEmpty())
        .collect(Collectors.toMap(Entry::getKey, Entry::getValue));

If you’re on Java 8, replace Map.entry() with new AbstractMap.SimpleEntry().