我的 StreamEx 库现在有 headTail()
操作,它解决了这个问题:
public static StreamEx<Integer> sieve(StreamEx<Integer> input) {
return input.headTail((head, tail) ->
sieve(tail.filter(n -> n % head != 0)).prepend(head));
}
该方法采用在流终端操作执行期间最多执行一次的方法。所以这个实现是懒惰的:在遍历开始之前,它不会计算任何东西,并且只计算请求的质数。接收第一个流元素和其余元素的流,并可以以所需的任何方式修改 。您可以将其与预定义的输入一起使用:headTail
BiFunction
BiFunction
head
tail
tail
sieve(IntStreamEx.range(2, 1000).boxed()).forEach(System.out::println);
但无限流也可以工作
sieve(StreamEx.iterate(2, x -> x+1)).takeWhile(x -> x < 1000)
.forEach(System.out::println);
// Not the primes till 1000, but 1000 first primes
sieve(StreamEx.iterate(2, x -> x+1)).limit(1000).forEach(System.out::println);
还有使用和谓词串联的替代解决方案:headTail
public static StreamEx<Integer> sieve(StreamEx<Integer> input, IntPredicate isPrime) {
return input.headTail((head, tail) -> isPrime.test(head)
? sieve(tail, isPrime.and(n -> n % head != 0)).prepend(head)
: sieve(tail, isPrime));
}
sieve(StreamEx.iterate(2, x -> x+1), i -> true).limit(1000).forEach(System.out::println);
比较递归解决方案很有趣:它们能够生成多少素数。
@John McClean 解决方案 (StreamUtils
)
John McClean的解决方案并不懒惰:你不能用无限的流来喂养它们。所以我只是通过试错找到了最大允许上限()(之后StackOverflowError发生):17793
public void sieveTest(){
sieve(IntStream.range(2, 17793).boxed()).forEach(System.out::println);
}
@John McClean 解决方案(可流式传输
)
public void sieveTest2(){
sieve(Streamable.range(2, 39990)).forEach(System.out::println);
}
将上限提高到以上会导致 StackOverflowError。39990
@frhack解决方案(LazySeq
)
LazySeq<Integer> ints = integers(2);
LazySeq primes = sieve(ints); // sieve method from @frhack answer
primes.forEach(p -> System.out.println(p));
结果:卡在素数之后 = 巨大的堆分配和垃圾回收占 90% 以上。从53323前进到53327花了几分钟,所以等待更多似乎不切实际。53327
@vidi解决方案
Prime.stream().forEach(System.out::println);
结果:堆栈溢出素数 = 之后的错误。134417
我的解决方案 (StreamEx)
sieve(StreamEx.iterate(2, x -> x+1)).forEach(System.out::println);
结果:堆栈溢出素数 = 之后的错误。236167
@frhack解决方案 (rxjava
)
Observable<Integer> primes = Observable.from(()->primesStream.iterator());
primes.forEach((x) -> System.out.println(x.toString()));
结果:堆栈溢出素数 = 之后的错误。367663
@Holger解决方案
IntStream primes=from(2).filter(i->p.test(i)).peek(i->p=p.and(v->v%i!=0));
primes.forEach(System.out::println);
结果:堆栈溢出素数 = 之后的错误。368089
我的解决方案(带谓词串联的 StreamEx)
sieve(StreamEx.iterate(2, x -> x+1), i -> true).forEach(System.out::println);
结果:堆栈溢出素数 = 之后的错误。368287
因此,三个涉及谓词串联的解决方案获胜,因为每个新条件仅增加 2 个堆栈帧。我认为,它们之间的差异很小,不应该被视为定义赢家。然而,我更喜欢我的第一个StreamEx解决方案,因为它更类似于Scala代码。