如何延迟连接流?

2024-04-03

我正在尝试实现一个在其实现中使用其自身的另一个实例的流。该流前面有一些常量元素(使用 IntStream.concat),因此只要串联流惰性地创建非常量部分,这应该就可以工作。我认为使用StreamSupport.intStream 重载采用供应商 https://docs.oracle.com/javase/8/docs/api/java/util/stream/StreamSupport.html#intStream-java.util.function.Supplier-int-boolean-与 IntStream.concat (其中“创建一个延迟连接的流” https://docs.oracle.com/javase/8/docs/api/java/util/stream/IntStream.html#concat-java.util.stream.IntStream-java.util.stream.IntStream-)应该足够懒,只在需要元素时才创建第二个分割器,但即使创建流(不评估它)也会溢出堆栈。如何延迟连接流?


我正在尝试从以下位置移植流式素数筛这个答案 https://stackoverflow.com/a/10733621/3614835进入Java。该筛子使用其自身的另一个实例(ps = postponed_sieve()在 Python 代码中)。如果我破坏最初的四个常量元素(yield 2; yield 3; yield 5; yield 7;)到他们自己的流中,很容易将生成器实现为分割器:

/**
 * based on https://stackoverflow.com/a/10733621/3614835
 */
static class PrimeSpliterator extends Spliterators.AbstractIntSpliterator {
    private static final int CHARACTERISTICS = Spliterator.DISTINCT | Spliterator.IMMUTABLE | Spliterator.NONNULL | Spliterator.ORDERED | Spliterator.SORTED;
    private final Map<Integer, Supplier<IntStream>> sieve = new HashMap<>();
    private final PrimitiveIterator.OfInt postponedSieve = primes().iterator();
    private int p, q, c = 9;
    private Supplier<IntStream> s;
    PrimeSpliterator() {
        super(105097564 /* according to Wolfram Alpha */ - 4 /* in prefix */,
                CHARACTERISTICS);
        //p = next(ps) and next(ps) (that's Pythonic?)
        postponedSieve.nextInt();
        this.p = postponedSieve.nextInt();
        this.q = p*p;
    }

    @Override
    public boolean tryAdvance(IntConsumer action) {
        for (; c > 0 /* overflow */; c += 2) {
            Supplier<IntStream> maybeS = sieve.remove(c);
            if (maybeS != null)
                s = maybeS;
            else if (c < q) {
                action.accept(c);
                return true; //continue
            } else {
                s = () -> IntStream.iterate(q+2*p, x -> x + 2*p);
                p = postponedSieve.nextInt();
                q = p*p;
            }
            int m = s.get().filter(x -> !sieve.containsKey(x)).findFirst().getAsInt();
            sieve.put(m, s);
        }
        return false;
    }
}

我第一次尝试 primes() 方法返回一个 IntStream,它将常量流与新的 PrimeSpliterator 连接起来:

public static IntStream primes() {
    return IntStream.concat(IntStream.of(2, 3, 5, 7),
            StreamSupport.intStream(new PrimeSpliterator()));
}

调用 primes() 会导致 StackOverflowError,因为 primes() 始终实例化 PrimeSpliterator,但 PrimeSpliterator 的字段初始值设定项始终调用 primes()。然而,StreamSupport.intStream 的重载需要一个供应商,这应该允许延迟创建 PrimeSpliterator:

public static IntStream primes() {
    return IntStream.concat(IntStream.of(2, 3, 5, 7),
            StreamSupport.intStream(PrimeSpliterator::new, PrimeSpliterator.CHARACTERISTICS, false));
}

然而,我却得到了一个具有不同回溯的 StackOverflowError (在重复时进行了修剪)。请注意,递归完全发生在对 primes() 的调用中——终端操作 iterator() 永远不会在返回的流上调用。

Exception in thread "main" java.lang.StackOverflowError
    at java.util.stream.StreamSpliterators$DelegatingSpliterator$OfInt.<init>(StreamSpliterators.java:582)
    at java.util.stream.IntPipeline.lazySpliterator(IntPipeline.java:155)
    at java.util.stream.IntPipeline$Head.lazySpliterator(IntPipeline.java:514)
    at java.util.stream.AbstractPipeline.spliterator(AbstractPipeline.java:352)
    at java.util.stream.IntPipeline.spliterator(IntPipeline.java:181)
    at java.util.stream.IntStream.concat(IntStream.java:851)
    at com.jeffreybosboom.projecteuler.util.Primes.primes(Primes.java:22)
    at com.jeffreybosboom.projecteuler.util.Primes$PrimeSpliterator.<init>(Primes.java:32)
    at com.jeffreybosboom.projecteuler.util.Primes$$Lambda$1/834600351.get(Unknown Source)
    at java.util.stream.StreamSpliterators$DelegatingSpliterator.get(StreamSpliterators.java:513)
    at java.util.stream.StreamSpliterators$DelegatingSpliterator.estimateSize(StreamSpliterators.java:536)
    at java.util.stream.Streams$ConcatSpliterator.<init>(Streams.java:713)
    at java.util.stream.Streams$ConcatSpliterator$OfPrimitive.<init>(Streams.java:789)
    at java.util.stream.Streams$ConcatSpliterator$OfPrimitive.<init>(Streams.java:785)
    at java.util.stream.Streams$ConcatSpliterator$OfInt.<init>(Streams.java:819)
    at java.util.stream.IntStream.concat(IntStream.java:851)
    at com.jeffreybosboom.projecteuler.util.Primes.primes(Primes.java:22)
    at com.jeffreybosboom.projecteuler.util.Primes$PrimeSpliterator.<init>(Primes.java:32)
    at com.jeffreybosboom.projecteuler.util.Primes$$Lambda$1/834600351.get(Unknown Source)
    at java.util.stream.StreamSpliterators$DelegatingSpliterator.get(StreamSpliterators.java:513)
    at java.util.stream.StreamSpliterators$DelegatingSpliterator.estimateSize(StreamSpliterators.java:536)
    at java.util.stream.Streams$ConcatSpliterator.<init>(Streams.java:713)
    at java.util.stream.Streams$ConcatSpliterator$OfPrimitive.<init>(Streams.java:789)
    at java.util.stream.Streams$ConcatSpliterator$OfPrimitive.<init>(Streams.java:785)
    at java.util.stream.Streams$ConcatSpliterator$OfInt.<init>(Streams.java:819)
    at java.util.stream.IntStream.concat(IntStream.java:851)
    at com.jeffreybosboom.projecteuler.util.Primes.primes(Primes.java:22)

如何足够懒惰地连接流以允许流在其实现中使用自身的另一个副本?


您显然认为 Streams API 将其惰性保证扩展到了 spliterator 的实例化;这是不正确的。它期望能够在实际消费开始之前随时实例化流的分割器,例如只是为了找出流的特征和报告的大小。消费仅通过调用开始trySplit, tryAdvance, or forEachRemaining.

考虑到这一点,您可以在需要之前初始化推迟的筛选。您无法使用其任何结果,直到else if参与tryAdvance。因此,将代码移至最后可能的时刻,以保证正确性:

@Override
public boolean tryAdvance(IntConsumer action) {
    for (; c > 0 /* overflow */; c += 2) {
        Supplier<IntStream> maybeS = sieve.remove(c);
        if (maybeS != null)
            s = maybeS;
        else {
            if (postponedSieve == null) {
              postponedSieve = primes().iterator();
              postponedSieve.nextInt();
              this.p = postponedSieve.nextInt();
              this.q = p*p;
            }
            if (c < q) {
              action.accept(c);
              return true; //continue

我认为,有了这个改变,即使你第一次尝试primes()应该管用。

如果您想继续使用当前的方法,您可以使用以下习惯用法:

Stream.<Supplier<IntStream>>of(
  ()->IntStream.of(2, 3, 5, 7),
  ()->intStream(new PrimeSpliterator()))
.flatMap(Supplier::get);

你可能会发现这给了你足够多的懒惰。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何延迟连接流? 的相关文章

随机推荐

  • 2 个 IndexedSlices 不支持高效 allreduce

    我正在尝试在多个 GPU 上运行子类 Keras 模型 代码按预期运行 但是在代码执行过程中出现以下 警告 2 个 IndexedSlices 不支持高效 allreduce 这是什么意思 我遵循 Tensorflow 2 0 Beta 指
  • 为什么 CSS 光标属性不适用于样式化滚动条?

    我设计了一个滚动条 but 光标指针不工作 即使我把 important webkit scrollbar width 0 3vw height 20px padding 2px cursor pointer important Handl
  • 两个 WPF 应用程序之间的通信

    我有两个 WPF 应用程序 我需要这两个应用程序能够相互通信 我只需要这些应用程序相互发送一些通知 仅此而已 我已经找到了两种技术 一种是使用WCF 另一种是使用DDE 但对我来说 这些对于我的要求来说似乎太复杂了 请建议最简单的方法是什么
  • Internet Explorer中跨域POST请求ajax

    我正在使用 jQuery 1 7 2 并且想向另一个域发出 POST 请求 它必须是 POST 请求 但这确实无法在 Internet Explorer 中工作 我在IE9上试过 它适用于所有其他浏览器 我有这个脚本
  • Java中将short转换为byte[]

    我怎样才能转换short 2 个字节 到 Java 中的字节数组 例如 short x 233 byte ret new byte 2 应该是这样的 但不确定 0xFF lt lt 8 x gt gt 0 EDIT 您还可以使用 java
  • 查找我的数据库的 DSN?

    我有一个 SQL 数据库 想要使用 VBA 连接到它以支持一些旧功能 我正在使用 ADODB 连接 需要知道我的数据库 DSN 是什么 我怎样才能找到这个 我正在使用 SQL Server 2008 谢谢 D A DSN 数据源名称 htt
  • Laravel 从嵌套关系中取出一个数组

    我只需要得到roomnumber从以下查询返回的数组 roomnumbers Room with floorroomcount gt function query query gt with roomnumber gt get gt whe
  • java队列中Queue.Poll()返回null但Queue.size()>0

    My code while Memo qRcv size gt 0 MessageReceived msg Memo qRcv poll 然后我得到了 2014 03 01 11 09 36 DEBUG Thread 16 threadQu
  • 如何将时间序列数据中的y%m%d%H格式转换为“%Y%m%d %H:%M:%S”

    我如何转换y m d H格式化为 Y m d H M S 我的日期从 1970 年到 2010 年 部分来自评论 如果您可以相应地修改问题 那就太好了 似乎这不是格式化的情况 y vs Y或空格 分隔符 但是strptime POSIX t
  • C谜题:用有偏差的硬币制造公平的硬币

    如何确定函数在以下情况下返回 0 或 1 的概率 Let the function A返回 0 与 概率 40 和 1 有概率 60 生成一个function B和 概率 50 50 仅使用function A only 我想到了以下几点
  • Java读取文件,如果不存在则创建它

    这是我的代码 public String path public String fileName public static void readData throws IOException try path myPath fileName
  • 具有固定大小的 Blackberry VerticalFieldManager:滚动问题

    我试图拥有一个带有修复标题 带有某些字段的管理器 和可滚动内容 自定义字段列表 的全屏用户界面 这个想法是模拟一种可滚动列表 为此 我制作了一个接受 maxHeight 屏幕高度 标题高度 的自定义 VerticalFieldManager
  • NSPopover 内的 NSTableview 看起来与独立的不同

    我创建了一个ListView类 这是一个非常简单的Tableview 如果我用 IB 实例化它 一切看起来都很好 如果我以编程方式实例化它也是一样 如果我在一个内部以编程方式实例化它NSPopover 我的桌子的每一行都有浅灰色背景 这是从
  • 为什么 form.submit() 不起作用?

    我在页面中有以下片段 我一生都无法弄清楚为什么单击button1元素时表单没有提交 我在 IE 中收到错误消息 指出该对象不支持此属性或方法 我将 document poform 放入警报中 它会警报表单对象 我感觉我可能错过了一些非常明显
  • 某些设备上的 Android 中出现“没有这样的表”问题

    我在 Android 应用程序中使用外部数据库 它在所有模拟器和三星真实设备上运行良好 但是当我检查宏碁智能手机时 我的应用程序崩溃并出现以下异常 android database sqlite SQLiteException no suc
  • 可变结构与类?

    我不确定是否使用可变结构或可变类 我的程序存储一个包含很多对象的数组 我注意到使用类会使所需的内存量增加一倍 但是 我希望对象是可变的 并且有人告诉我使用可变结构是邪恶的 这就是我的类型 struct or class Block publ
  • 将 Flash (AS3) 数据保存为 XML

    我在互联网上 包括 Stack Overflow 花了好几个小时 试图找到一个可靠的 可行的示例 将 Flash 中的信息保存到 XML 文件中 我想获取两种不同类型对象的位置并将每个对象的列表导出到 XML 我们将调用这些对象ball a
  • PHP 5.3.3 中的 ini_set("memory_limit") 根本不起作用

    我之前有过这样的工作 echo ini get memory limit n ini set memory limit 256M echo ini get memory limit n 这将输入 32M 256M 在通过命令行执行的 php
  • 如何在 C# HttpClient 中循环调用分页 URL 以从 JSON 结果下载所有页面

    我的第一个问题 所以请友善 我正在使用C HttpClient调用作业 API 端点 这是端点 Jobs API Endpoint 不需要密钥 点击即可 http service dice com api rest jobsearch v1
  • 如何延迟连接流?

    我正在尝试实现一个在其实现中使用其自身的另一个实例的流 该流前面有一些常量元素 使用 IntStream concat 因此只要串联流惰性地创建非常量部分 这应该就可以工作 我认为使用StreamSupport intStream 重载采用