如何从java 8中的双嵌套映射中收集对象?

时间:2016-01-09 04:37:04

标签: java java-8 java-stream

我打算利用在我的程序中使用并行流的好处,我想替换这样的循环:

    for (int gridY = gridYFrom; gridY <= gridYTo; gridY++) {
        for (int gridX = gridXFrom; gridX <= gridXTo; gridX++) {
            coordinates.add(Coordinate.from(gridX, gridY));
        }
    }

有这样的事情:

    IntStream.rangeClosed(gridYFrom, gridYTo).parallel().map(y -> 
        IntStream.rangeClosed(gridXFrom, gridXTo).mapToObj(x -> {
            return Coordinate.from(x, y);
        }
    )).collect(Collectors.toSet());

我的问题是,我在这里遇到cyclic inference错误。我理解我应该从内部地图返回int以与外部地图兼容,但我想返回Coordinate对象(因此mapToObj调用)。是否可以使用collect而不使用forEach构造?

2 个答案:

答案 0 :(得分:4)

你想做的是这些事情:

首先,当您在map上致电IntStream时,它仍然会返回IntStream,这不是您想要的。相反,也可以使用mapToObj作为外部循环。

其次,内部循环返回一个不完整的Stream<Coordinate>,我认为这也不是你想要的。所以,你也想在那上面调用.collect(Collectors.toSet())

最后,您需要将flatMap Stream<Set<Coordinate>>合并为一个Stream<Coordinate>,然后您可以使用

stream.flatmap(Set::stream);

这一切归结为

IntStream.rangeClosed(0, 10).parallel().mapToObj(y ->
    IntStream.rangeClosed(0, 20).mapToObj(x -> 
        Coordinate.from(x,y)).collect(Collectors.toSet())
).flatMap(Set::stream).collect(Collectors.toSet());

编辑: 实际上,忘记内在的collect。只需flatmapStream::sequential

你最终会得到

IntStream.rangeClosed(0, 10).parallel().mapToObj(y -> 
    IntStream.rangeClosed(0, 20).mapToObj(x -> 
        Coordinate.from(x, y))).flatMap(Stream::sequential).collect(Collectors.toSet())

答案 1 :(得分:2)

您不需要收集两次。 问题是IntStream与java中的任何其他流不同,遗憾的是。因此,您必须先将其转换为普通流,然后才能执行flatMap

IntStream.rangeClosed(gridYFrom, gridYTo)
   .mapToObj( y -> Integer.valueOf(y) )
   .flatMap( y -> 
      IntStream.rangeClosed(gridXFrom, gridXTo)
         .mapToObj(x ->  Coordinate.from(x,y))
   )
   .collect(Collectors.toSet())