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

Ste*_*ano 2 java lambda java-8 java-stream

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

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

如何使用Java 8流和过滤器过滤嵌套循环?

Java 8筛选器映射<String,List <Employee >>

在地图上过滤

这是我用来写我的例子的代码


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 -> {  ... });


Run Code Online (Sandbox Code Playgroud)

这是我的结果代码



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


Run Code Online (Sandbox Code Playgroud)

我坚持该示例的所有尝试都存在关于无法识别结果类型的问题。这是我能够达到的最佳效果(不起作用):

speedsPerRoadPerSegment.entrySet().stream()
                            .flatMap(road-> road.getValue().entrySet()
                            .stream().flatMap(
                                    segment -> segment .getValue()
                                    .stream()
                                    .max(Comparator.comparing(PartialSpeed::getnVelFfs))
                                    ));
Run Code Online (Sandbox Code Playgroud)

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

Hol*_*ger 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());
Run Code Online (Sandbox Code Playgroud)

此用途Collections.max,而不是一个嵌套的流操作,如果集合为空时将抛出一个异常(就像调用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());
Run Code Online (Sandbox Code Playgroud)