当前位置: 首页 > 知识库问答 >
问题:

是否可以在Java8中创建一个由递归定义的无限增长的惰性集合?

柳俊健
2023-03-14

我可以创建一个递归闭包:

static IntUnaryOperator fibo;
fibo = 
    (i) -> 
    i<2 ? 1 : fibo.applyAsInt(i-1)+ fibo.applyAsInt(i-2);
IntStream fi;
fi=IntStream.iterate(0, i -> fi[i-1]+fi[i-2]);

因此,我需要一些可以通过索引来处理的构造。作为fibo(i)

编辑。显然,解决方案不能是流,因为流不能使用两次。我不想在每次调用F(I)时重复所有的计算。

共有1个答案

范华清
2023-03-14

看来你是在要求这样的东西:

public class Fibonacci extends AbstractList<BigInteger> {
    @Override
    public Stream<BigInteger> stream() {
        return Stream.iterate(new BigInteger[]{ BigInteger.ONE, BigInteger.ONE },
           p->new BigInteger[]{ p[1], p[0].add(p[1]) }).map(p -> p[0]);
    }
    @Override
    public Iterator<BigInteger> iterator() {
        return stream().iterator();
    }
    @Override
    public int size() {
        return Integer.MAX_VALUE;
    }
    @Override
    public BigInteger get(int index) {
        return stream().skip(index).findFirst().get();
    }
}

它可以通过list接口访问(它没有实现randomaccess有很好的原因),因此,您可以通过get(n)请求第n个值。注意,get的实现提示了如何在integer.max_value之后的位置获取值。只需使用stream().skip(position).findfirst().get()

当心!这个列表是无限的,正如你所要求的。不要向它请求对所有元素都起作用的东西,例如,甚至不要向它请求toString()。但是像下面这样的事情会很顺利的工作:

System.out.println(new Fibonacci().subList(100, 120));
for(BigInteger value: new Fibonacci()) {
    System.out.println(value);
    if(someCondition()) break;
}   
public class Fibonacci extends AbstractList<BigInteger> {
    final Map<BigInteger,BigInteger> values=new HashMap<>();

    public Fibonacci() {
        values.put(BigInteger.ONE, BigInteger.ONE);
        values.put(BigInteger.ZERO, BigInteger.ONE);
    }

    @Override
    public BigInteger get(int index) {
        return get(BigInteger.valueOf(index));
    }
    public BigInteger get(BigInteger index) {
        return values.computeIfAbsent(index, ix ->
            get(ix=ix.subtract(BigInteger.ONE)).add(get(ix.subtract(BigInteger.ONE))));
    }

    @Override
    public Stream<BigInteger> stream() {
        return Stream.iterate(BigInteger.ZERO, i->i.add(BigInteger.ONE)).map(this::get);
    }
    @Override
    public Iterator<BigInteger> iterator() {
        return stream().iterator();
    }
    @Override
    public int size() {
        return Integer.MAX_VALUE;
    }
}

我在这里使用biginteger作为键/索引来满足(理论上)无限的要求,尽管我们也可以使用long键用于所有实际用途。关键是最初的空存储:(现在示例性地使用long):

final Map<Long,BigInteger> values=new HashMap<>();

它使用应结束每个递归的值预先初始化(除非由于已计算的值而提前结束):

values.put(1L, BigInteger.ONE);
values.put(0L, BigInteger.ONE);

然后,我们可以通过以下方式请求一个懒散计算的值:

public BigInteger get(long index) {
    return values.computeIfAbsent(index, ix -> get(ix-1).add(get(ix-2)));
}
LongStream.range(0, Long.MAX_VALUE).mapToObj(this::get);

这创建了一个流,它只是“实际上是无限的”,而上面使用biginteger的完整示例类理论上是无限的…

映射将记住序列的每个计算值。

 类似资料:
  • 问题内容: 我可以创建一个递归闭包: 但是,当然,它仅作为示例具有意义。为了有用,此类集合应该保留已经计数过的元素,并对其进行get()而不重新计数。首先,元素的计数应以惰性方式进行。因此,无需再计算一次成员。这样,我们将得到一个看起来像递归定义序列的结构,并且该结构将是快速且可重用的。 当我开始学习Java 8时,我认为Stream可以这样工作。但事实并非如此,因为流不能被使用两次。 我考虑了以

  • 让我们假设我有一个实体类Foo,它包含一些字段、getter、setter和构造函数。例如: 然后我想知道a或b何时改变。我知道javaFX中有一个ObjectProperty。所以我要创建对象属性: 然后,为了了解a和b字段的更改,我添加了ChangeListener: 然后进行实验: 工作正常,但下一行: 不调用侦听器。原因很清楚。最后一行实际上没有更改Foo对象(引用保持不变)。 我有一些可

  • 问题内容: 在数学课上,我们学习了如何定义新的运算符。例如: 这定义了法律。对于x和y的任何实数,x y是x + 2y。 范例:。 可以在JavaScript中定义这样的运算符吗?我知道函数可以胜任: 但我想使用以下语法: 代替这个: 哪个是最接近这个问题的解决方案? 问题答案: 最简洁的答案是不。ECMAScript(标准JS所基于的)不支持运算符重载。 可以使用sweet.js之类的第三方工具

  • 我想清除大部分别名定义的PowerShell会话,除了cd、sort、mkdir等常见别名 完成会话后,我希望恢复所有以前已知的别名。 无需卸载模块或注销CmdLets。我只想为我的会话清除别名命名空间。 我可以在如下列表中指定允许的别名: 如何保存和恢复别名? 或 如何启动一个干净的PoSh并只加载基本别名? 以下几行来自我的示例模块。 用法示例: 不幸的是,dir Alias:在调用我的脚本后

  • 嗨,我只是想知道有没有可能创建一个通用类来确认ObserveObject协议,它可以被多个ContentView使用。 如果我能做到这一点,那么我将能够使我的ContentView和Model类完全通用和可重用。 我希望实现的一个例子: 如果我能做到这一点,任何类都可以实现ContentViewModelType,并成为ContentView的模型,使其通用且可重用。举个例子 但是当我尝试初始化C

  • 我对卡蒙达很陌生,还在努力弄清楚什么是可能的。 Camunda BPM至少提供了三种创建自定义表单的方法: 向你致意,伊万