7

Similar to my previous question here, the User objects I have are these

new User("ayush","admin",23)
new User("ashish","guest",19) 
new User("ashish","admin",20) 
new User("garima","guest",29)
new User("garima","super",45)
new User("garima","guest",19)

Now I am trying to get the name to varying ages trend for these users. But I need to filter them above a threshold age. I could get the trend using

Map<String, List<Integer>> userNameAndAgeTrend = users.stream().collect(Collectors.groupingBy(user-> user.getName(), Collectors.mapping(u-> u.getAge(), toList())));

this gives me {ashish=[19, 20], garima=[29, 45, 19], ayush=[23]}. But I am unable to filter the List properly using threshold for example 21 years in my situation using such grouping. Can someone please help?

Also, using .filter(user -> user.getAge() > 21) gives no mapping for ashish, which is what I want to store too. I can use Java10 installed on my machine and trying the suggested solutions.

0

3 Answers 3

9

Stream.filter

You could use filter as

Map<String, List<Integer>> userNameAndAgeTrend = users.stream()
        .filter(a -> a.getAge() > 21) // only above 21
        .collect(Collectors.groupingBy(User::getName, Collectors.mapping(User::getAge, Collectors.toList())));

As confirmed by you in comments, this would give you as output

{garima=[29, 45], ayush=[23]}

Collectors.filtering

If you're looking for all the names, you could also use Collectors.filtering since which explicitly calls out a similar behavior (formatting mine) :

Using a filtering collector as shown above would result in a mapping from that department to an empty Set.

If a stream filter() operation were done instead, there would be no mapping for that department at all.

Its usage should look something like:

Map<String, List<Integer>> userNameAndAgeTrend = users.stream()
        .collect(Collectors.groupingBy(User::getName, Collectors.mapping(User::getAge, 
                        Collectors.filtering(age -> age > 21, Collectors.toList()))));

and the output now would be

{ashish=[], garima=[29, 45], ayush=[23]}
Sign up to request clarification or add additional context in comments.

2 Comments

Using this I get {garima=[29, 45], ayush=[23]}, but I wanted the user "ashish" as well with no trends.
@Mani if you could update to Java9 you could use an inbuilt JDK utility for it or else probably implement your own. Aside: I would suggest making that as an edit to your question.
5

if you want to filter before grouping:

users.stream()
     .filter(u -> u.getAge() > 21) //<--- apply the filter operation
     ...

filter is an intermediate operation which enables one to "keep the elements that satisfy the provided predicate" and exclude others that don't.

So, after the filter operation you have a new stream consisting of only the elements that pass the provided predicate. in this case only users where their age is older than 21.


if you want to filter after grouping (not to be confused with filter in a stream, this is a little different)

the filtering collector as of JDK9:

users.stream()
     .collect(groupingBy(User::getName, 
            filtering(u -> u.getAge() > 21, 
                   mapping(User::getAge, toList()))));

see, the accepted answer here for a JDK8 implementation.

With stream’s filter above, the values are filtered first and then it’s grouped. in other words, after filtering we have "no trace" of them.

However, with the filtering collector as of JDK9 we can maintain a trace.

4 Comments

Using this I get {garima=[29, 45], ayush=[23]}, but I wanted the user "ashish" as well with no trends.
@Mani maybe you're after the filtering collector as of jdk9?
Let me try filtering. Stupid me, forgot to update in question, I can use until Java 10 installed on my laptop.
Thank you, the filtering works as you all pointed. Just see a difference in sequence of call from the other answer here, I hope that doesn't matter much. They both run similarily for me.
2

You need to add the .filter() operation before the .collect() one

Map<String, List<Integer>> userNameAndAgeTrend = 
                      users.stream()
                           .filter(user -> user.getAge() > 21)
                           .collect(Collectors.groupingBy(user-> user.getName(), Collectors.mapping(u-> u.getAge(), toList())));

5 Comments

Using this I get {garima=[29, 45], ayush=[23]}, but I wanted the user "ashish" as well with no trends.
@Mani what did you mean by "with no trends"?
There should be mapping with empty list for age of ashish for the current input, like ashish=[] @Andrew
@Mani seems like you're after users.stream() .collect(groupingBy(User::getName, filtering(u -> u.getAge() > 21, mapping(User::getAge, toList()))));
Thank you for the answer. But the other solutions works for me.

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.