使用lambda从嵌套在嵌套地图中的一组列表中构建最大值列表

时间:2019-06-05 11:15:10

标签: java lambda java-8 java-stream

我是Java 8的新手,我需要重写一段旧代码来实现新的算法。 任务是过滤每个列表具有最大速度的对象。 列表嵌套在地图内部:道路的根地图,其中包含路段的地图,每条路段的地图都包含一系列对象,每个对象描述一个时间间隔的测得速度。我需要找到每个列表的所有最大速度。

我找到了以下链接,这些链接看起来像我的问题,但是我无法适应它们,而且我不确定我的尝试是否能正确解决我的问题。

How do you filter nested loops using Java 8 streams and filters?

Java 8 Filter Map<String,List<Employee>>

Filter on map of map

这是我作为示例编写我的代码


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))
                                    ));

如您所见,我刚刚用foreaches替换了旧的for循环。我想了解如何直接从lambda表达式中获取最大元素列表。

1 个答案:

答案 0 :(得分:6)

通常,无论您使用循环还是流,在处理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());