2

I have a map

Map<Integer, List<Person>> personsById 

and a predicate function callbak

(person) -> person.getPersonID() > 10 && person.blabla() !=null 

I need to filter the map based on the predicate and I came up with below code which doesn't modify the List

map.entrySet().stream() .filter(entry -> entry.getValue().stream().anyMatch(predicate)) .collect(Collectors.toMap(Map.Entry::getKey,Map.Entry::getValue)) 

However the above code doesnt actually filter the List ext: {id: 100, [{personID: 100}, {personID: 50}, {personID: 2}] I can still seee personID: 2 in the list. Is there a way I can modify the value in the list to return filtered List or persons?. Any pointers on it in java 8 will be greatly useful.

P.s: Plz ignore any typos in the typed code I came up with.

Edit: I got the answer

map.entrySet() .stream() .collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().stream().filter(predicate).collect(Collectors.toList()))) 
8
  • I think I found the answer. map..entrySet() .stream() .collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().stream().filter(predicate).collect(Collectors.toList()))) Commented Feb 17, 2018 at 0:39
  • then post your answer in the answer section and accept it :) Commented Feb 17, 2018 at 0:42
  • The reason why your initial approach was incorrect is because here -> .filter(entry -> entry.getValue().stream().anyMatch(predicate)) you're basically saying "given a map entry, create a stream from the entry value (a List<Person> in this case) then if any of the people in the list match the provided predicate then retain the entire entry". hence were getting unexpected results. Commented Feb 17, 2018 at 1:27
  • What happens if your predicate filters out all elements of the list? Are you OK keeping entries with an empty list as the value? Or would you like to also filter out that entry from the map? Commented Feb 17, 2018 at 22:05
  • Currently I am ok with keeping the map key with empty results, However I would love to see another answer that will even filter the keys and when nothing matches gives null as result. If you have better solution then help me with it. Commented Feb 18, 2018 at 1:43

2 Answers 2

3

I found the below approach to be working well for me. Any better solutions are welcome to post a reply and say why its better. Currently, this code returns a map keys with an empty list if no match is found, (If you have a solution which can eliminate keys from the result and return null when nothing matches that will be good too).

 map.entrySet() .stream() .collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue() .stream().filter(predicate) .collect(Collectors.toList())) ) 
Sign up to request clarification or add additional context in comments.

Comments

0

If you don't care about you're inital map then you can use following snippet, which iterates over the values stored in the map and then checks if an item in the list needs to be removed when it doesn't fullfil the predicate:

map.values().forEach(list -> list.removeIf(predicate.negate())); 

What i have to mention though is, that this works only for mutable lists. For imutable ones an unchecked UnsupportedOperationException is thrown at runtime.

Doc: Collection.removeIf(Predicate)

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.