gpt4 book ai didi

java - Java 8 中流的笛卡尔积作为流(仅使用流)

转载 作者:塔克拉玛干 更新时间:2023-11-03 03:14:00 24 4
gpt4 key购买 nike

我想创建一个方法来创建一个元素流,这些元素是多个给定流的笛卡尔积(在末尾由二元运算符聚合为相同类型)。请注意,参数和结果都是流,不是集合。

例如,对于 {A, B}{X, Y} 这两个流,我希望它产生值流 {AX, AY , BX, BY}(简单的连接用于聚合字符串)。到目前为止,我想出了这段代码:

private static <T> Stream<T> cartesian(BinaryOperator<T> aggregator, Stream<T>... streams) {
Stream<T> result = null;

for (Stream<T> stream : streams) {
if (result == null) {
result = stream;
} else {
result = result.flatMap(m -> stream.map(n -> aggregator.apply(m, n)));
}
}

return result;
}

这是我想要的用例:

Stream<String> result = cartesian(
(a, b) -> a + b,
Stream.of("A", "B"),
Stream.of("X", "Y")
);

System.out.println(result.collect(Collectors.toList()));

预期结果:AX, AY, BX, BY

另一个例子:

Stream<String> result = cartesian(
(a, b) -> a + b,
Stream.of("A", "B"),
Stream.of("K", "L"),
Stream.of("X", "Y")
);

预期结果:AKX、AKY、ALX、ALY、BKX、BKY、BLX、BLY

但是,如果我运行代码,我会得到这个错误:

IllegalStateException:流已被操作或关闭

流在哪里消费?通过 flatMap?可以轻松修复吗?

最佳答案

在您的示例中传递流永远不会比传递列表更好:

private static <T> Stream<T> cartesian(BinaryOperator<T> aggregator, List<T>... lists) {
...
}

然后像这样使用它:

Stream<String> result = cartesian(
(a, b) -> a + b,
Arrays.asList("A", "B"),
Arrays.asList("K", "L"),
Arrays.asList("X", "Y")
);

在这两种情况下,您都从可变参数创建隐式数组并将其用作数据源,因此惰性是虚构的。您的数据实际上存储在数组中。

在大多数情况下,生成的笛卡尔积流比输入长得多,因此实际上没有理由使输入惰性化。例如,有五个包含五个元素的列表(总共 25 个),您将得到包含 3125 个元素的结果流。所以在内存中存储 25 个元素不是很大的问题。实际上在大多数实际情况下它们已经存储在内存中。

为了生成笛卡尔积流,您需要不断地“回放”所有流(第一个流除外)。要倒回,流应该能够一次又一次地检索原始数据,或者以某种方式缓冲它们(你不喜欢)或者从源(集合、数组、文件、网络、随机数等)中再次抓取它们。 ) 并一次又一次地执行所有中间操作。如果您的源和中间操作很慢,那么惰性解决方案可能比缓冲解决方案慢得多。如果您的来源无法再次生成数据(例如,随机数生成器无法生成与之前生成的相同的数字),您的解决方案将是不正确的。

然而,完全懒惰的解决方案是可能的。只是不使用流,而是使用流供应商:

private static <T> Stream<T> cartesian(BinaryOperator<T> aggregator,
Supplier<Stream<T>>... streams) {
return Arrays.stream(streams)
.reduce((s1, s2) ->
() -> s1.get().flatMap(t1 -> s2.get().map(t2 -> aggregator.apply(t1, t2))))
.orElse(Stream::empty).get();
}

这个解决方案很有趣,因为我们创建并减少供应商流以获取最终供应商并最终调用它。用法:

Stream<String> result = cartesian(
(a, b) -> a + b,
() -> Stream.of("A", "B"),
() -> Stream.of("K", "L"),
() -> Stream.of("X", "Y")
);
result.forEach(System.out::println);

关于java - Java 8 中流的笛卡尔积作为流(仅使用流),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32631602/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com