В потоке объектов - как отфильтровать уникальные элементы с наивысшим приоритетом? - PullRequest
0 голосов
/ 03 июня 2019


У меня есть проблема, которая кажется, что это должно быть просто решить с помощью потоков Java, но до сих пор у меня не получилось (по крайней мере, любым простым способом).
У меня есть поток объектов

class Person {
    String name;
    int age;
}
List<Person> personList = Arrays.asList(
            new Person("Eric", 10),
            new Person("Eric", 20),
            new Person("Anna", 20),
            new Person("John", 20),
            new Person("Mary", 5),
            new Person("Mary", 20),
            new Person("Mary", 10));

Как бы я мог манипулировать этим списком с помощью потоков, чтобы в итоге я получил список (или любую другую коллекцию), содержащую каждого человека (Эрика, Анну, Джона и Мэри) вместе с их самым высоким возрастом.

[Person{name='Eric', age=20}, Person{name='Anna', age=20}, Person{name='John', age=20}, Person{name='Mary', age=20}]

Очевидным было бы правильно реализовать Equals / Hash, но с этим я придумываю только первое появление каждого человека. Я также посмотрел на наборы деревьев и компараторы, но безуспешно.

Что было бы самым элегантным способом решить эту проблему?
Заранее спасибо.

Ответы [ 4 ]

3 голосов
/ 03 июня 2019

Если вы не хотите добавлять hashCode() и equals() к Person классу, то вам, вероятно, нужно сопоставить имя String. Вы можете использовать Collectors.groupingBy, Collectors.mapping и Collectors.maxBy, чтобы найти максимальный возраст:

Map<String, Optional<Integer>> collect = personList.stream()
    .collect(groupingBy(Person::getName, 
                mapping(Person::getAge, maxBy(Integer::compare))));

или как указал Хольгер:

Map<String, Integer> collect = personList.stream()
    .collect(toMap(Person::getName, Person::getAge, Math::max));

, который создаст:

{Eric=Optional[20], John=Optional[20], Mary=Optional[20], Anna=Optional[20]}
2 голосов
/ 04 июня 2019

В качестве альтернативы вы можете использовать toMap на основе имени в качестве key (для уникальности, как я понимаю из вопроса) и собирать Person в качестве value с при объединении на основе age в качестве приоритета. Это может быть достигнуто как:

Collection<Person> personWithAgeAsPriority = personList.stream()
        .collect(Collectors.toMap(Person::getName, Function.identity(), // name as key and person as values
                BinaryOperator.maxBy(Comparator.comparingInt(Person::getAge)))) // compare age and choose
        .values();
0 голосов
/ 03 июня 2019

Самое простое для чтения решение - это два шага:

int maxAge =
    personList.stream().mapToInt(p -> p.age).max().getAsInt();

Collection<Person> oldestPersons =
    personList.stream().filter(p -> p.age == maxAge).collect(
        Collectors.toList());

Если вы настаиваете на том, чтобы сделать это за один проход, я бы сгруппировал людей по возрасту в TreeMap и использовал бы этот TreeMap.самая высокая запись (то есть запись, соответствующая наибольшему возрасту):

Collection<Person> oldestPersons =
    personList.stream().collect(Collectors.groupingBy(p -> p.age,
        TreeMap::new, Collectors.toList())).lastEntry().getValue();
0 голосов
/ 03 июня 2019

Ниже приведен более традиционный подход для достижения этой цели:

public class TestClass {

  public static void addToMap(Map<String, Integer> map, String name, Integer age){

      if(map.get(name) == null || map.get(name) < age)
          map.put(name, age);

          }

  public static void main(String[] args) {
      // TODO Auto-generated method stub
      Map<String, Integer> map = new HashMap<String, Integer>();
      addToMap(map, "Eric", 10);
      addToMap(map, "Eric", 20);
      addToMap(map, "Anna", 20);
      addToMap(map, "John", 20);
      addToMap(map, "Mary", 5);
      addToMap(map, "Mary", 30);
      addToMap(map, "Mary", 10);

      for(Map.Entry<String, Integer> entry : map.entrySet())
          System.out.println("[" + entry.getKey() + ":" + entry.getValue() + "]");
  }

Вы можете внести изменения в этот код для обработки объекта класса Person. Надеюсь, это поможет !!!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...