Как отфильтровать возраст при группировке на карте со списком

Как и в моем предыдущем вопросе здесь, Пользователь объекты, которые у меня есть, это

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)

Теперь я пытаюсь дать название тренду разного возраста для этих пользователей. Но мне нужно отфильтровать их старше threshold возраста. Я мог бы получить тренд, используя

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

это дает мне {ashish=[19, 20], garima=[29, 45, 19], ayush=[23]}. Но я не могу правильно отфильтровать список, используя порог, например 21 год в моей ситуации, используя такую ​​группировку. Может кто-нибудь помочь?

Кроме того, использование .filter(user -> user.getAge() > 21) не дает сопоставления для ashish, что я тоже хочу сохранить. Я могу использовать Java10, установленную на моем компьютере, и пробовать предложенные решения.


person Mani    schedule 19.12.2018    source источник


Ответы (3)


Stream.filter

Вы можете использовать filter как

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

Как вы подтвердили в комментариях, это даст вам результат

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

Collectors.filtering

Если вы ищете все имена, вы также можете использовать Collectors.filtering, так как java-9, который явно вызывает подобное поведение (моё форматирование):

Использование коллектора filtering, как показано выше, приведет к сопоставлению этого отдела с пустым набором.

Если бы вместо этого была выполнена потоковая операция filter(), для этого отдела вообще не было бы сопоставления.

Его использование должно выглядеть примерно так:

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

и вывод сейчас будет

{ashish=[], garima=[29, 45], ayush=[23]}
person Naman    schedule 19.12.2018
comment
Используя это, я получаю {garima=[29, 45], ayush=[23]}, но я также хотел пользователя ashish без трендов. - person Mani; 20.12.2018
comment
@Mani, если бы вы могли обновиться до Java9, вы могли бы использовать для этого встроенную утилиту JDK или, возможно, реализовать свою собственную. В сторону: я бы предложил сделать это как редактирование вашего вопроса. - person Naman; 20.12.2018

если вы хотите filter перед группировкой:

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

filter — это промежуточная операция, которая позволяет «сохранить элементы, удовлетворяющие предоставленному предикату», и исключить другие, не удовлетворяющие.

Итак, после операции filter у вас есть новый поток, состоящий только из элементов, которые передают предоставленный предикат. в этом случае только пользователи, возраст которых старше 21 года.


если вы хотите filter после группировки (не путать с filter в потоке, это немного другое)

сборщик filtering начиная с JDK9:

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

см., принятый ответ здесь для реализации JDK8 .

Для потока filter выше значения сначала фильтруются, а затем группируются. другими словами, после фильтрации у нас «нет следов».

Однако с помощью коллектора filtering от JDK9 мы можем поддерживать трассировку.

person Ousmane D.    schedule 19.12.2018
comment
Используя это, я получаю {garima=[29, 45], ayush=[23]}, но я также хотел пользователя ashish без трендов. - person Mani; 20.12.2018
comment
@ Мани, может быть, тебе нужен сборщик filtering с jdk9? - person Ousmane D.; 20.12.2018
comment
Попробую фильтровать. Глупый я, забыл обновить, о котором идет речь, я могу использовать, пока на моем ноутбуке не будет установлена ​​​​Java 10. - person Mani; 20.12.2018
comment
Спасибо, фильтрация работает, как вы все указали. Просто посмотрите на разницу в последовательности вызова от другого ответа здесь, надеюсь, это не имеет большого значения. Они оба работают одинаково для меня. - person Mani; 20.12.2018

Вам нужно добавить операцию .filter() перед .collect().

Map<String, List<Integer>> userNameAndAgeTrend = 
                      users.stream()
                           .filter(user -> user.getAge() > 21)
                           .collect(Collectors.groupingBy(user-> user.getName(), Collectors.mapping(u-> u.getAge(), toList())));
person azro    schedule 19.12.2018
comment
Используя это, я получаю {garima=[29, 45], ayush=[23]}, но я также хотел пользователя ashish без трендов. - person Mani; 20.12.2018
comment
@ Мани, что ты имел в виду под отсутствием трендов? - person Andrew Tobilko; 20.12.2018
comment
Для текущего ввода должно быть сопоставление с пустым списком возраста ashish, например ashish=[] @Andrew - person Mani; 20.12.2018
comment
@Мани, кажется, ты ищешь users.stream() .collect(groupingBy(User::getName, filtering(u -> u.getAge() > 21, mapping(User::getAge, toList())))); - person Ousmane D.; 20.12.2018
comment
Спасибо за ответ. Но другие решения работают для меня. - person Mani; 20.12.2018