使用Stream<Collection<T>>
时,我想将Java 8 Stream API中的常用方法应用于流中每个集合中T类型的每个元素。正如标题所述,我主要想要映射元素,但当然所有其他方法(例如filter(Predicate)
或allMatch(Predicate)
)也是有意义的。
考虑存储多个矩形瓦片的2D板的示例。每个图块由它在板上占据的(x,y)位置定义。
List<Position> tile1 = Lists.asList(tile1Pos1, tile1Pos2, ...)
List<Position> tile2 = Lists.asList(tile2Pos1, tile2Pos2, ...)
...
List<List<Position>> board = Lists.asList(tile1, tile2, ...)
旋转电路板时,我想转换瓷砖的所有位置。我需要将相同的x应用于y和y到x映射函数到每个位置。但是,我必须保留瓷砖和它们各自位置之间的关联。
目前,我正在使用Stream<List<Position>> streamOfCollections
:
List<List<Position>> rotatedBoard = board.stream().map(tile -> tile.stream().map(Position::mapperFunctionRotate).collect(toList())).collect(toList());
请注意,我保留了原始数据布局。每个位置仍然与它所属的一个特定区块相关联。
对任何Stream<Collection<T>>
进行推广我想修改类型T的所有单个元素,同时将它们保存在集合中。
理想情况下,我希望能够在Java Stream API中执行与board.stream().mapIndividually(Position::mapperFunctionRotate)
具有类似方法签名的flatMap
,但不会展平我的列表流。< / p>
有没有方便的方法来简化上述映射功能?
我也在寻找能够完成工作的库或框架。在我看来,Java API不支持这样的事情,我认为其他库实际上是这个问题的主要范围。
我已经查看了 guava ,它提供了像Multimap<K, V>
这样的数据结构,表现得像Map<K, Collection<V>>
,但我没有找到Java Stream API的扩展。< / p>
答案 0 :(得分:3)
你在这里寻找平面图吗?
.stream().flatMap(Collection::stream).collect(Collectors.toList());
答案 1 :(得分:2)
目前尚不清楚你的目标是什么。您显示的解决方案已经是规范解决方案。如果你想重复做类似的事情,你可以将它抽象成一个方法:
public static <T,R> List<List<R>> applyToAll(
Collection<? extends Collection<? extends T>> source,
Function<? super T, ? extends R> op) {
return source.stream()
.map(c -> c.stream().map(op).collect(Collectors.toList()))
.collect(Collectors.toList());
}
您可以在特定情况下使用
List<List<Position>> rotatedBoard = applyToAll(board, Position::mapperFunctionRotate);
通常,“转换集合的每个元素并生成集合”没有快捷方式,因此,在嵌套上下文中也没有相同内容的快捷方式。
当然,您可以创建自己的并在顶上实现嵌套变体:
public static <T,R> List<R> mapAll(
Collection<T> source, Function<? super T, ? extends R> op) {
return source.stream().map(op).collect(Collectors.toList());
}
...
List<List<Position>> rotatedBoard
= mapAll(board, l -> mapAll(l, Position::mapperFunctionRotate));
如果您认为,感觉FP不够,您可以将其声明为
public static <T,R,C extends Collection<T>>
Function<C, List<R>> mapAll(Function<? super T, ? extends R> op) {
return source -> source.stream().map(op).collect(Collectors.toList());
}
像
一样使用Function<List<List<Position>>,List<List<Position>>> f
= mapAll(mapAll(Position::mapperFunctionRotate));
List<List<Position>> rotatedBoard = f.apply(board);
遗憾的是,Java需要在这里明确声明函数类型,否则mapAll(mapAll(Position::mapperFunctionRotate)).apply(board)
会成为一个很好的用例,特别是因为它很容易扩展到更多维度。但Java(当前)类型推断无法解决这个问题。
但是,您可以将上述两种mapAll
方法合并到
List<List<Position>> rotatedBoard = mapAll(board, mapAll(Position::mapperFunctionRotate));