首先,我是一名JavaScript程序员,对Java8还是相当陌生,并尝试了新的功能。
由于我精通JS编码,因此我实现了自己的JS惰性函数库以进行概念验证。
https://github.com/kenokabe/spacetime
使用该库,我可以编写无限自然数序列和斐波那契,如下所示:
JavaScript
var spacetime = require('./spacetime');
var _ = spacetime.lazy();
var natural = _(function(n) //memoized automatically
{
return n; // Natural numbers is defined as the `n`th number becomes `n`
});
var natural10 = _(natural)
.take(10)
.compute(function(x)
{
console.log(x);
});
//wrap a recursive function to memoize
// must be at the definition in the same scope
var fib = _(function(n)
{
if (n <= 1)
return 1; // as the Fib definition in Math
else
return fib(n - 2) + fib(n - 1); // as the Fib definition in Math
});
var fib10 = _(fib)
.take(10)
.compute(function(x)
{
console.log(x);
});
足够清楚。关键是我可以按原样定义Natural/Fibonacci无限序列作为数学定义,然后再通过惰性求值来计算无限序列的所需部分。
所以,现在我想知道我是否可以对Java8使用相同的方式。
对于自然顺序,我在这里发布了另一个问题。
Infinite sequence of Natural numbers with Java8 generator
定义自然序列的一种方法是使用Java8的
iterator
:Java8
IntStream natural = IntStream.iterate(0, i -> i + 1);
natural
.limit(10)
.forEach(System.out::println);
我观察到
IntStream natural = IntStream.iterate(0, i -> i + 1);
是数学意义上自然数的合理定义。但是,我想知道是否可以像以前一样定义它,也就是说,
JavaScript
var natural = _(function(n) //memoized automatically
{
return n; // Natural numbers is defined as the `n`th number becomes `n`
});
因为这看起来更简洁。不幸的是,答案表明,即使我们使用
generate
,也可能无法实现。另外,
IntStream.iterate
不适合斐波那契数列。我在网上搜索斐波那契的
generate
不定序列,我发现的最佳结果是http://blog.informatech.cr/2013/05/08/memoized-fibonacci-numbers-with-java-8/
Java8
private static Map<Integer,Long> memo = new HashMap<>();
static {
memo.put(0,0L); //fibonacci(0)
memo.put(1,1L); //fibonacci(1)
}
//And for the inductive step all we have to do is redefine our Fibonacci function as follows:
public static long fibonacci(int x) {
return memo.computeIfAbsent(x, n -> fibonacci(n-1) + fibonacci(n-2));
}
这不是一个无限的序列(Java8中的惰性
Stream
)。和
Providing Limit condition on Stream generation
Java8
Stream.generate(new Supplier<Long>() {
private long n1 = 1;
private long n2 = 2;
@Override
public Long get() {
long fibonacci = n1;
long n3 = n2 + n1;
n1 = n2;
n2 = n3;
return fibonacci;
}
}).limit(50).forEach(System.out::println);
这是一个无限序列(Java8中的惰性
Stream
),您可以说它被定义为Math。但是我不喜欢这种实现,因为,如您所见,获得序列有很多内部值(value),例如
n1
n2
n3
然后fibonacci
,因此代码结构复杂,而您需要控制可变状态,这是反功能方式-与数学定义不同,它可能没有被记住。所以,这是我的问题。使用Java8
Stream
,有没有办法编写代码以简洁的数学方式定义斐波那契的无穷序列,并带有诸如JavaScript
var fib = _(function(n)
{
if (n <= 1)
return 1; // as the Fib definition in Math
else
return fib(n - 2) + fib(n - 1); // as the Fib definition in Math
});
感谢您的想法。
最佳答案
您可以使用基于 map 的备忘录fibonacci(x)并从中生成无限流,如下所示:
LongStream fibs = IntStream.iterate(1, i->i+1).mapToLong(i -> fibonacci(i));
但是,制作无限斐波纳契数流的最简单方法是这样的:
LongStream fibs = Stream.iterate(
new long[]{1, 1},
f -> new long[]{f[1], f[0] + f[1]}
).mapToLong(f -> f[0]);
正如您所链接的文章所指出的那样,“无限”实际上意味着“直到长时间的溢出”,而这很快就会发生。如果要生成数百个斐波那契数,请用BigInteger替换long:
Stream<BigInteger> bigFibs = Stream.iterate(
new BigInteger[]{BigInteger.ONE, BigInteger.ONE},
f -> new BigInteger[]{f[1], f[0].add(f[1])}
).map(f -> f[0]);