Предположим, у нас есть класс человека с полями:

Class Person {
  private String name;
  private Integer id (this one is unique);
}

И тогда у нас есть List<Person> people такой, что:

['Jerry', 993]
['Tom', 3]
['Neal', 443]
['Jerry', 112]
['Shannon', 259]
['Shannon', 533]

Как я могу сделать новый List<Person> uniqueNames таким, чтобы он фильтровал только уникальные имена И сохранял наивысший идентификатор этого имени.

Итак, конечный список будет выглядеть так:

['Jerry', 993]
['Tom', 3]
['Neal', 443]
['Shannon', 533]
0
stackerstack 15 Окт 2021 в 00:09

3 ответа

Лучший ответ

Collectors.groupingBy + Collectors.maxBy должен помочь построить карту людей, сгруппированных по имени, а затем выбрать максимальное значение:

List<Person> persons = Arrays.asList(
    new Person("Jerry", 123),
    new Person("Tom", 234),
    new Person("Jerry", 456),
    new Person("Jake", 789)
);

List<Person> maxById = persons
    .stream()
    .collect(Collectors.groupingBy(
        Person::getName, 
        Collectors.maxBy(Comparator.comparingInt(Person::getID))
    ))
    .values() // Collection<Optional<Person>>
    .stream() // Stream<Optional<Person>>
    .map(opt -> opt.orElse(null))
    .collect(Collectors.toList());

System.out.println(maxById);

Выход:

[789: Jake, 234: Tom, 456: Jerry]
4
Alex Rudenko 14 Окт 2021 в 21:37

Вы можете попробовать:

import static java.util.stream.Collectors.*;

persons.stream()
       .collect(
          groupingBy(
            Person::getName, 
            collectingAndThen(
              maxBy(Person::getId), 
              Optional::get
            )
          )
       )
       .values()
       ;
  • Вы группируете по имени
  • Затем вы запрашиваете максимальное количество сгруппированных людей (на имя)
  • Затем вы возвращаете значения (поскольку groupingBy возвращает Map<String, Optional<Person>>, вызов collectAndThen вызывает Optional::get).

Обратите внимание, что в этом списке будут перечислены уникальные имена, но не будут дублироваться имена.

2
NoDataFound 14 Окт 2021 в 21:26

Вы можете использовать Collectors#toMap вот так.

record Person(String name, Integer id) {}

public static void main(String[] args) {
    List<Person> input = List.of(
        new Person("Jerry", 993),
        new Person("Tom", 3),
        new Person("Neal", 443),
        new Person("Jerry", 112),
        new Person("Shannon", 259),
        new Person("Shannon", 533));

    List<Person> output = input.stream()
        .collect(Collectors.toMap(Person::name, Function.identity(),
            (a, b) -> a, LinkedHashMap::new))
        .values().stream().toList();

    for (Person e : output)
        System.out.println(e);
}

Выход:

Person[name=Jerry, id=993]
Person[name=Tom, id=3]
Person[name=Neal, id=443]
Person[name=Shannon, id=259]

Вы можете опустить , LinkedHashMap::new, если вас не волнует порядок.

0
saka1029 14 Окт 2021 в 21:47