Stream of cartesian product of other streams, each element as a List?

柔情痞子 提交于 2019-12-09 17:37:02

问题


How can I implement a function using Java 8 to take some number of streams, and produce a stream in which each element is a list consisting of one member of the Cartesian product of the streams?

I've looked at this question -- that question uses an aggregator that is a BinaryOperator (taking two items of like type and producing an item of the same type). I'd like the items in the end result to be Lists rather than the types of the elements in the input streams.

Concretely, supposing my desired function is called product, the following:

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

should print:

[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]

Ideally, I'd like for this operation to be as lazy as possible. For example, if the input streams are produced by Stream.generate(), it'd be great if the suppliers of those streams weren't executed until absolutely needed.


回答1:


A possible solution is as follows:

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);
}

The product-call returns a Stream<List<String>> result which prints as

[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]


来源:https://stackoverflow.com/questions/41528446/stream-of-cartesian-product-of-other-streams-each-element-as-a-list

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!