Как вы конвертируете картуна картув потоках java внутри собирать? - PullRequest
0 голосов
/ 30 мая 2018

Представьте, что у вас есть список людей, Робертс, Полс, Ричардс и т. Д., Это люди, сгруппированные по имени в Map<String, List<Person>>.Вы хотите найти самого старшего Пола, Роберта и т.д. ... Вы можете сделать это так:

public static void main(String... args) {
        List<Person> people = Arrays.asList(
                new Person(23, "Paul"),
                new Person(24, "Robert"),
                new Person(32, "Paul"),
                new Person(10, "Robert"),
                new Person(4, "Richard"),
                new Person(60, "Richard"),
                new Person(9, "Robert"),
                new Person(26, "Robert")
        );

        Person dummy = new Person(0, "");
        var mapping = people.stream().collect(groupingBy(Person::getName, reducing(dummy, (p1, p2) -> p1.getAge() < p2.getAge() ? p2 : p1)));
        mapping.entrySet().forEach(System.out::println);
    }

Скажем, я хочу получить отображение в виде Map<String, Integer> вместо Map<String, Person>, Я могу сделать это так:

var mapping = people.stream().collect(groupingBy(Person::getName, mapping(Person::getAge, reducing(0, (p1, p2) -> p1 < p2 ? p2 : p1))));

Шаги выше:

  • Сгруппировать по имени в Map<String/*Name*/, List<Person>>
  • Отобразить, что List<Person> вList<Integer>
  • Найти максимальное целое число в этих списках.

Мне было интересно, как это сделать:

  • Сгруппировать по имени в Map<String, List<Person>>
  • Найдите самого старого человека в названии каждой группы, получив Map<String, Person>
  • Преобразование Map<String, Person> в Map<String, Integer>.И я хочу сделать все это внутри цепочки группировки By, уменьшая и сопоставляя.

Это "псевдокод":

var mapping = people.stream().collect(groupingBy(Person::getName, reducing(dummy, (p1, p2) -> p1.getAge() < p2.getAge() ? p2 : p1 /*, have to write some other collector factory method here*/)));

Как мне этого добиться?

Ответы [ 3 ]

0 голосов
/ 30 мая 2018

Это проще сделать с версией с тремя аргументами toMap collector :

people.stream().collect(toMap(
        Person::getName, 
        Person::getAge, 
        Integer::max
    ));
0 голосов
/ 30 мая 2018

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

final Map<String, Integer> oldestPersonByName = people.stream()
        .collect(Collectors.groupingBy(Person::getName, Collectors.reducing(0, Person::getAge, Integer::max)));

Для сокращения вы должны передать элемент идентификации, функцию отображения ибинарный оператор, используемый для уменьшения, в данном случае max.

0 голосов
/ 30 мая 2018

Я думаю, что это будет похоже на следующее, также используя maxBy вместо reducing.

people.stream().collect(
    groupingBy(
        Person::getName,
        collectingAndThen(
            maxBy(Comparator.comparing(Person::getAge)),
            (Optional<Person> max) -> max.get().getAge()
        )
    )
);
...