Построить список максимальных значений из набора списков, вложенных во вложенные карты с помощью лямбды - PullRequest
2 голосов
/ 05 июня 2019

Я новичок в Java 8, и мне нужно переписать старый кусок кода для реализации нового алгоритма. Задача состоит в том, чтобы отфильтровать объект, который имеет максимальную скорость для каждого списка. Списки вложены в карты: корневая карта дорог, которая содержит карты сегментов дороги, а каждая карта сегментов дороги содержит список объектов, каждый из которых описывает измеренную скорость за определенный промежуток времени. Мне нужно найти все максимальные скорости для каждого списка.

Я нашел следующие ссылки, которые выглядят как моя проблема, но я не могу их адаптировать, и я не уверен, что мои попытки решают мою проблему правильно.

Как вы фильтруете вложенные циклы, используя потоки и фильтры Java 8?

Карта фильтра Java 8 >

Фильтр на карте карты

это код, который я использовал в качестве примера для написания моего


Map<String, Map<String, Employee>> employeeMap =
                            employeeMap.entrySet()
                                       .stream()
                                       .collect(toMap(Map.Entry::getKey,
                                                      e -> e.getValue().entrySet().stream()
                                                      .filter(emp -> !emp.getValue().getState().equals("MI"))
                                                      .collect(toMap(Map.Entry::getKey, Map.Entry::getValue))));


for(Car car : cars) {
                        for (Engine engine : car.getEngines()) {
                            for (Part part : engine.getParts()) {
                                // ...
                            }
                        }
                    }


                    cars.stream()
                        .flatMap(car -> car.getEngines().stream())
                        .flatMap(engine -> engine.getParts().stream())
                        .forEach(part -> {  ... });


это мой полученный код



Map<Integer, Map<Integer, List<PartialSpeed>>> speedsPerRoadPerSegment; 


ArrayList<PartialSpeed> maxSpeedPerSegment = new ArrayList<PartialSpeed>();
                    speedsPerRoadPerSegment.entrySet().stream()
                            .forEach(road-> road.getValue().entrySet()
                            .stream()
                            .forEach(segment ->
                            {
                                Optional<PartialSpeed> result = segment.getValue().stream()
                                .max(Comparator.comparing(PartialSpeed::getnVelFfs));
                                maxSpeedPerSegment.add(result.get());
                            }));


Все мои попытки придерживаться этого примера имели проблемы с тем, что типы результатов не распознаются. Это лучшее (не работает), которого я смог достичь:

speedsPerRoadPerSegment.entrySet().stream()
                            .flatMap(road-> road.getValue().entrySet()
                            .stream().flatMap(
                                    segment -> segment .getValue()
                                    .stream()
                                    .max(Comparator.comparing(PartialSpeed::getnVelFfs))
                                    ));

Как видите, я только что заменил старые циклы for на foreaches. Я хотел бы понять, как получить список максимальных элементов непосредственно из лямбда-выражения.

1 Ответ

6 голосов
/ 05 июня 2019

Как правило, независимо от того, используете ли вы цикл или поток, при обработке Map вы должны выбрать правильное представление коллекции, keySet(), entrySet() или values(), в зависимости от того, какие элементы вам действительно нужны.Так как вас интересуют только значения, не используйте entrySet().

Затем примените правильную операцию терминала к потоку, чтобы получить окончательный результат:

List<PartialSpeed> maxSpeedPerSegment =
    speedsPerRoadPerSegment.values().stream()
        .flatMap(m -> m.values().stream())
        .map(list -> Collections.max(list, Comparator.comparing(PartialSpeed::getnVelFfs)))
        .collect(Collectors.toList());

Этоиспользует Collections.max вместо вложенной операции Stream, которая будет генерировать исключение, если коллекция пуста (точно так же, как безоговорочно будет вызываться get() на Optional).

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

List<PartialSpeed> maxSpeedPerSegment =
    speedsPerRoadPerSegment.values().stream()
        .flatMap(m -> m.values().stream())
        .filter(list -> ! list.isEmpty())
        .map(list -> Collections.max(list, Comparator.comparing(PartialSpeed::getnVelFfs)))
        .collect(Collectors.toList());
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...