【问题标题】:Build a list of maximum values from a set of lists nested inside nested maps with lambda使用 lambda 从嵌套在嵌套映射中的一组列表构建最大值列表
【发布时间】:2019-06-05 11:15:10
【问题描述】:

我是 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 表达式中获取最大元素列表。

【问题讨论】:

  • Map&lt;Road, Map&lt;Segment, List&lt;PartialSpeed&gt;&gt;&gt;speedsPerRoadPerSegment 的类型?
  • @Hadi j yes ,道路和路段只是整数 ID。我已经编辑了代码。如果有不清楚的地方请询问,我已将变量名称翻译成英文以使其更易于理解。
  • 试试这个speedsPerRoadPerSegment.entrySet() .forEach(road -&gt; road.getValue().entrySet() .stream() .map(segment -&gt; segment.getValue() .stream().max(Comparator.comparing(PartialSpeed::getnVelFfs))). map(Optional::get) .forEach(maxSpeedPerSegment ::add));我没测试过。
  • 虽然 Holger 的回答很好,但也可以试试这个speedsPerRoadPerSegment.entrySet() .stream() .flatMap(road -&gt; road.getValue().entrySet().stream()) .map(Map.Entry::getValue) .filter(list-&gt;!list.isEmpty()) .map(segment -&gt; segment.stream() .max(Comparator.comparing(PartialSpeed::getnVelFfs))) .map(Optional::get).collect(Collectors.toList());
  • @Hadi J +1 你的最后一个例子。它非常有用:我意识到我的错误是没有从 Map.Entry 中获得价值。我会坚持使用 Holger 解决方案,因为正如他所说,我必须选择正确的集合视图。

标签: java lambda java-8 java-stream


【解决方案1】:

通常,无论您使用循环还是流,在处理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 操作,如果集合为空,它将引发异常(就像在 Optional 上无条件调用 get() 一样)。

如果可能出现空列表,您可以预先过滤它们:

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

【讨论】:

    猜你喜欢
    • 2017-05-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-27
    • 2020-04-02
    • 2018-04-21
    • 2010-11-21
    相关资源
    最近更新 更多