其他流的笛卡尔积流,每个元素作为一个列表?

8
如何使用Java 8实现一个函数来获取多个流,并生成一个流,其中每个元素都是流的笛卡尔积中的一个成员的列表?我查看了这个问题:这个问题 - 这个问题使用一个聚合器,它是一个二元运算符(取两个相同类型的项目并生成一个相同类型的项目)。 我想最终结果中的项应为List而不是输入流中元素的类型。
具体而言,假设我的期望函数名为product,则以下内容:
Stream<List<String>> result =
    product(
        Stream.of("A", "B", "C", "D"),
        Stream.of("I", "J", "K"),
        Stream.of("Y", "Z")
    );

result.forEach(System.out::println);

应该打印:

[A, I, Y]
[A, I, Z]
[A, J, Y]
[A, J, Z]
[A, K, Y]
[A, K, Z]
[B, I, Y]
...
[D, K, Y]
[D, K, Z]

理想情况下,我希望这个操作尽可能地懒惰。例如,如果输入流是由Stream.generate()生成的,那么如果能够在绝对需要的时候才执行这些流的提供方,那就太棒了。

2个回答

1
一种可能的解决方案如下:
private static <T> Stream<List<T>> product(Stream<T>... streams) {
    if (streams.length == 0) {
        return Stream.empty();
    }
    List<List<T>> cartesian = streams[streams.length - 1]
            .map(x -> Collections.singletonList(x))
            .collect(Collectors.toList());
    for (int i = streams.length - 2; i >= 0; i--) {
        final List<List<T>> previous = cartesian;
        cartesian = streams[i].flatMap(x -> previous.stream().map(p -> {
            final List<T> list = new ArrayList<T>(p.size() + 1);
            list.add(x);
            list.addAll(p);
            return list;
        })).collect(Collectors.toList());
    }
    return cartesian.stream();
}

public static void main(String... args) {
    final Stream<List<String>> result =
            product(
                    Stream.of("A", "B", "C", "D"),
                    Stream.of("I", "J", "K"),
                    Stream.of("Y", "Z")
            );

    result.forEach(System.out::println);
}

产品调用返回一个Stream<List<String>>结果,打印如下:
[A, I, Y]
[A, I, Z]
[A, J, Y]
[A, J, Z]
[A, K, Y]
[A, K, Z]
[B, I, Y]
[B, I, Z]
[B, J, Y]
[B, J, Z]
[B, K, Y]
[B, K, Z]
[C, I, Y]
[C, I, Z]
[C, J, Y]
[C, J, Z]
[C, K, Y]
[C, K, Z]
[D, I, Y]
[D, I, Z]
[D, J, Y]
[D, J, Z]
[D, K, Y]
[D, K, Z]

0
你可以实现类似这样的东西:
List<Stream<String>> listStreams = List.of(
        Stream.of("A", "B", "C", "D"),
        Stream.of("I", "J", "K"),
        Stream.of("Y", "Z"));

Stream<List<String>> streamLists = listStreams.stream()
        // represent each list element as SingletonList<Object>
        .map(stream -> stream.map(Collections::singletonList))
        // summation of pairs of inner lists
        .reduce((stream1, stream2) -> {
            // list of lists from second stream
            List<List<String>> list2 = stream2.collect(Collectors.toList());
            // append to the first stream
            return stream1.flatMap(inner1 -> list2.stream()
                    // combinations of inner lists
                    .map(inner2 -> {
                        List<String> list = new ArrayList<>();
                        list.addAll(inner1);
                        list.addAll(inner2);
                        return list;
                    }));
        }).orElse(Stream.empty());

// output
streamLists.forEach(System.out::println);

输出:

[A, I, Y]
[A, I, Z]
[A, J, Y]
[A, J, Z]
[A, K, Y]
[A, K, Z]
[B, I, Y]
[B, I, Z]
[B, J, Y]
[B, J, Z]
[B, K, Y]
[B, K, Z]
[C, I, Y]
[C, I, Z]
[C, J, Y]
[C, J, Z]
[C, K, Y]
[C, K, Z]
[D, I, Y]
[D, I, Z]
[D, J, Y]
[D, J, Z]
[D, K, Y]
[D, K, Z]

另请参阅:查找两个列表的笛卡尔积


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接