Collectors.toMap напишите функцию слияния для свойства объекта, для которого не используется значение - PullRequest
6 голосов
/ 12 июня 2019

Я создаю Map<String,String> из List<Person>, используя поток java-8

persons.stream()
       .collect(Collectors.toMap(Person::getNationality, Person::getName, (name1, name2) -> name1)

Но в вышеупомянутом случае я хочу разрешить конфликт в имени, используя возраст человека. Есть ли способ передать функцию слияния что-то вокруг строк (age1, age2) -> // if age1 is greater than age2 return name1, else return name2?

Ответы [ 3 ]

8 голосов
/ 12 июня 2019

Чтобы выбрать человека в зависимости от его возраста, вам необходим экземпляр Person для запроса возраста. Вы не можете восстановить информацию после сопоставления Person с простым именем String.

Таким образом, вы должны сначала собрать людей, чтобы иметь возможность выбрать самых старых, а затем сопоставить их с именами:

persons.stream()
    .collect(Collectors.groupingBy(Person::getNationality, Collectors.collectingAndThen(
        Collectors.maxBy(Comparator.comparingInt(Person::getAge)),
        o -> o.get().getName())));
3 голосов
/ 12 июня 2019

Если вы не хотите использовать вспомогательную структуру данных, это возможно, если вы сначала сохраните информацию о персоне и выполните слияние на ее основе, а затем примените сопоставление:

public void test() {
    final List<Person> persons = new ArrayList<>();

    final BinaryOperator<Person> mergeFunction =
        (lhs, rhs) -> lhs.getAge() > rhs.getAge() ? lhs : rhs;

    final Function<Person, String> mapFunction = Person::getName;

    final Map<String, String> personNamesByNation =
        persons.stream()
            .collect(
                Collectors.groupingBy(Person::getNation, // KeyMapper Person.getNation: Map<String, List<Person>>
                    Collectors.collectingAndThen(
                        Collectors.collectingAndThen(
                            Collectors.reducing(mergeFunction), // Merge Persons into single value via merge function: Map<String, Optional<Person>>
                            Optional::get), // unwrap value: Map<String, Person>
                        mapFunction))); // apply map function afterwards: Map<String, String>
}
1 голос
/ 12 июня 2019

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

persons.stream()
       .sorted(Comparator.comparing(Person::getAge).reversed())
       .collect(Collectors.toMap(Person::getNationality, Person::getName, (n1, n2) -> n1));
...