映射Stream <collection <t>&gt;

时间:2016-11-18 12:31:57

标签: java collections java-stream

使用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>

2 个答案:

答案 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));