因此,我最近一直在处理Python,我正在设法在一个表达式中输出fibonacci序列的第n个数字。这是我到目前为止编写的代码:
(lambda f: f if f<2 else (f-1)+(f-2))(n)
# n == 1 -> 1
# n == 2 -> 1
# n == 3 -> 3
# n == 4 -> 5
# n == 5 -> 7
....
但是,正如我在上面评论的那样,这只是输出了一组奇数。我对为什么会发生这种情况感到困惑,因为如果我要将它重写为一个命名的lambda函数,它将如下所示:
f = lambda n: n if n<2 else f(f-1)+f(f-2)
# f(1) -> 1
# f(2) -> 1
# f(3) -> 2
# f(4) -> 3
...
# f(10) -> 55
...
现在,我添加Lambda标记的原因是我不确定这个问题是否属于简单理解Python如何处理这个问题的范畴。我读过一些关于lambda微积分中的Y组合子的文章,但对我来说,这是一门外语,我无法从我找到的关于lambda微积分的资源中得到任何东西。
现在,我尝试用一行代码来完成这个任务,而不是命名它,因为我想尝试将这个lambda函数放到列表理解中。所以做这样的事:
[(lambda f: f if f<2 else (f-1)+(f-2))(n) for n in range(10)]
并在fibonacci序列中创建第一个x数数组。
我要找的是一种用一个表达式来完成整件事情的方法,如果这属于Lambda微积分的范畴,我相信它是属于这个领域的,让人来解释它是如何工作的。
可以自由地用JavaScript、C#或其他支持Lambda函数的类似C语言提供答案。
编辑:--我找到了我想要做的事情的解决方案:
[(lambda f: (lambda x: f(lambda v: x(x)(v)))(lambda x: f(lambda v: x(x)(v))))(lambda f:(lambda n: n if n<2 else f(n-1)+f(n-2)))(y) for y in range(10)]
我知道这根本不实际,不应该使用这种方法,但我关心的是我能不能这样做,而不是如果我这样做的话。
发布于 2017-09-30 08:04:27
不如:
(lambda f: (4 << f * (3 + f)) // ((4 << 2 * f) - (2 << f) - 1) & ((2 << f) - 1))(n)
它没有按照通常的方式开始序列:
0, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, ...
但一旦你过了1点,你就没事了。您将在博客条目Fibonacci数的一个整数公式中找到详细的解释以及大量相关信息。
在我的系统中,@lehiester基于黄金比率的解决方案在F71上偏离了轨道,产生了308061521170130,而不是308061521170129,并且继续偏离那里。
发布于 2017-09-30 01:44:17
您需要将lambda分配给实际变量,然后调用lambda中的lambda:
>>> g = lambda f: f if f < 2 else g(f-1)+g(f-2)
>>> [g(n) for n in range(10)]
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
发布于 2017-09-30 15:51:19
我有一个符合你标准的单行解决方案,但这是我写过的最疯狂的代码之一。它不使用列表理解,但它将动态解决方案和lambda函数混合在一行中。
fib = (lambda n: (lambda fib: fib(fib, [], n, None))(lambda fib, arr, i, _: arr if i == 0 else fib(fib, arr, i-1, arr.append(1) if len(arr) < 2 else arr.append(arr[-1]+arr[-2]))))
只是为了解释一下。第一部分(lambda fib: fib(fib, [], n, None))
以lambda函数作为参数,然后使用它期望的参数调用它。这个技巧允许我们为lambda函数分配一个名称,并将这个名称传递给自己。这就是魔法。
第二部分,核心函数,lambda fib, arr, i, _: arr if i == 0 else fib(fib, arr, i-1, arr.append(1) if len(arr) < 2 else arr.append(arr[-1]+arr[-2])))
使用另一个技巧来实现动态解决方案。第一个参数fib
是对自身的引用,第二个参数arr
是包含我们的解决方案的数组,它是从左到右递归调用fib
精确的n
时间。当第三个参数i
变为0时,递归结束。第四个参数是一个丑陋的技巧:函数不使用它,但它用于调用arr
的追加方法。
这绝对是不那么优雅的解决方案,但也是最快的解决方案。我在下面报告N=500
的时间安排。
天真的解决方案是不可行的,但在这里您可以找到代码,以便每次计算一个元素(这可能是您希望将lambda函数和递归混合在一起的):
(lambda n: ((lambda fib: fib(fib,n+1))(lambda fib, i: (1 if i <= 2 else fib(fib,i-2) + fib(fib,i-1)))))(N)
@cdlane提出的解决方案:
%timeit [0, 1] + [(4<<n*(3+n)) // ((4<<2*n)-(2<<n)-1) & ((2<<n)-1) for n in range(N)][1:]
10 loops, best of 3: 88.3 ms per loop
@lehiester提出的解决方案:
%timeit [int(round((lambda n: ((1+5**0.5)**n-(1-5**0.5)**n)/(2**n*5**0.5))(x))) for x in range(N)]
1000 loops, best of 3: 1.49 ms per loop
我丑陋的解决方案:
%timeit (lambda n: (lambda fib: fib(fib, [], n, None))(lambda fib, arr, i, _: arr if i == 0 else fib(fib, arr, i-1, arr.append(1) if len(arr) < 2 else arr.append(arr[-1]+arr[-2]))))(N)
1000 loops, best of 3: 434 us per loop
另一个不使用递归的丑陋且更快的解决方案:
%timeit (lambda n: (lambda arr, fib_supp: [arr] + [fib_supp(arr) for i in xrange(n)])([], (lambda arr: arr.append(1) if len(arr) < 2 else arr.append(arr[-1]+arr[-2])))[0])(N)
1000 loops, best of 3: 346 us per loop
更新
最后,我找到了一种优雅的方法来构造单行函数。想法总是一样的,但是使用setitem方法而不是追加。我使用的一些技巧可以在这个链接上找到。这种方法有点慢,但至少是可读的:
%timeit (lambda n: (lambda arr, fib_supp: any(fib_supp(i, arr) for i in xrange(2,n)) or arr)([1] * n, (lambda i, arr: arr.__setitem__(i,(arr[i-1]+arr[i-2])))))(N)
1000 loops, best of 3: 385 us per loop
https://stackoverflow.com/questions/46498798
复制相似问题