[google/guava]添加 Streams.iterate(T seed, UnaryOperator f, Predicate stop)

2024-04-24 891 views
1

Stream 有两个参数版本,iterate它采用种子 ( T seed) 和迭代函数 ( UnaryOperator<T> f) 并通过重复应用该函数来生成无限流。这几乎是传统 for 循环的完美替代,只不过它缺少终止谓词。 Java 9 添加了takeWhile可用于终止以这种方式生成的流的功能,但不幸的是我们中的一些人还没有超越 Java 8。

<T> Stream<T> iterate(T seed, UnaryOperator<T> f, Predicate<T> stop)向实用程序类添加一个静态方法可能会很好Streams,它可以填补这个空白,至少在 Java 11 发布并被广泛认为稳定之前是这样。另一种(或可能是额外的)方法是向takeWhile同一个类添加一个静态方法,该方法将通过某些谓词限制 Stream,尽管这有点笨拙。

谢谢,如果您需要更多详细信息或任何说明,请告诉我。

回答

7

或者,支持扇出和扇入(终止)的 flatMap 变体?

static Stream<T> generate(T initial, Function<T, Stream<T>> iterate);

至此,iterate(seed, f, stop)可以表示为:

generate(seed, v -> stop(v) ? empty() : Stream.of(f.apply(v)));
8

@ Fluentfuture 是的,这会更通用。我想问题是 Guava 是否只想解决这个用例(提供一种使用 for 循环样式初始化器/转换器/终止器创建流的方法),或者提供更通用但不太适合该特定问题的东西。另外,由于该方法无法迭代实现,因此堆栈溢出不会成为问题吗?

0

对于这个特殊情况,您想到的用例是什么,@Diagoras?

个人认为 与iterate(initial, step, stop)太相似for (T v = initial; !stop(v); v = step(v)) {...},可能会引出一个问题:向普通的旧 for 循环引入函数方言是否会增加重量。

我想这forEach()是一个先例,尽管有for (T v : elements)。但话又说回来,由于 Stream 没有实现 Iterable,因此您无法在不forEach使用 API 的情况下轻松有效地迭代现有 Stream。

在实现方面,以下内容generate()应该在 Java 10(或者可能是 9+?)中工作,而不会出现堆栈溢出(尽管可能不是最有效的):

Stream<T> generate(T initial, Function<T, Stream<T>> step) {
  return concat(Stream.of(initial), step.apply(initial).flatMap(n -> generate(n, step)));
}
4

@flutterfuture 这几乎就是你所说的。我经常想要一个 for 循环风格的生成器,但又具有Stream.我可以在 Java 9+ ( Stream.iterate(() -> initial, previous -> step(previous)).takeWhile(!stop)) 上轻松实现这一点,但该语法对于其作用并不明确,并且在 Java 9 之前不可用。

由于 Guava 在类中具有许多用于 Java 9 之前的流式传输的有用方法Streams(例如,在 Java 9 中<T> stream(Optional<T> optional)被取代Optional#toStream()),我认为该方法非常适合。不过,如果您认为用例太小众,那么我们可以关闭这个问题。

4

出色地。这只是我个人的观察,因为我并不经常需要这样做。

让我们看看 Guava 维护者的想法。 :)

0

推测 API,我认为iterate(initial, step, stop)签名本身可能不够不言而喻。同样可能将谓词视为while代替,until因为它就是 for 循环的样子。

我认为添加两个类似的 API(例如iterateUntil和 )iterateWhile可能会带来太多好处而收效甚微。

另一方面,更通用的generate(initial, iterate)签名可用于创建不太模糊的语法,但您需要在本地代码库streamWhile()中添加两个帮助器和。streamUntil()

Function<T, Stream<T>> streamUntil(Predicate<T> condition, UnaryOperator<T> step) {
  return v -> condition.test(v) ? Stream.of(step.apply(v)) : Stream.empty();
}
Function<T, Stream<T>> streamWhile(Predicate<T> condition, UnaryOperator<T> step) {
  return streamUntil(condition.negate(), step);
}

然后:

generate(initial, streamUntil(this::shouldStop, this::nextValue));
generate(initial, streamWhile(this::shouldContinue, this::nextValue));