2016-01-09 62 views
1

我打算利用我的程序中使用並行數據流的好處,我想,以取代這樣一個循環:如何從java 8中的雙重嵌套地圖中收集對象?

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構造?

回答

4

你想要做的就是這些事情:

首先,當你在一個IntStream稱之爲map,它仍然會返回一個IntStream,這是不是你想要的。相反,也可以使用mapToObj作爲外部循環。

其次,內循環返回一個不完整的Stream<Coordinate>,我認爲這也不是你想要的。所以,你也要打電話給.collect(Collectors.toSet())

最後,你要flatMapStream<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()) 
+0

太好了,謝謝!我發現我需要收集兩次,但其他'mapToObj'仍然是一個問題。 –

+2

請檢查我的編輯。我完全忘了'Stream :: sequential'。 –

+2

爲什麼使用'Stream :: sequential'作爲平面映射內部流的函數?只需使用'flatMap(s - > s)'。 –

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()) 
+1

您可以使用'.boxed()'而不是'.mapToObj(y - > Integer.valueOf(y))' – Misha