如何使用列表理解创建斐波那契数列?

How can I create the fibonacci series using a list comprehension?

我是 python 的新手,我想知道是否可以使用 python 的列表理解功能生成斐波那契数列。我不知道列表理解是如何实现的。 我尝试了以下(目的是生成前五个斐波那契数):

series=[]
series.append(1)
series.append(1)
series += [series[k-1]+series[k-2] for k in range(2,5)]

这段代码抛出错误:IndexError: list index out of range.

让我知道是否有可能使用列表理解生成这样的系列。

你不能那样做:列表理解首先评估,然后将该列表添加到series.所以基本上就像你会写的那样:

series=[]
series.append(1)
series.append(1)
<b>temp = </b>[series[k-1]+series[k-2] for k in range(2,5)]
series<b> += temp</b>

然而,您可以通过使用 列表理解 来解决此问题,作为 强制副作用 的一种方式,例如:

series=[]
series.append(1)
series.append(1)
<b>[series.append(series[k-1]+series[k-2]) for k in range(2,5)]</b>

请注意,我们这里不将结果添加到系列。列表理解仅用于在 series 上调用 .append。然而,有些人认为带有副作用的列表推导式更容易出错:它不是很明确,如果不仔细做,往往会引入错误。

以 Willem van Onsem 所说的为基础:

如您所知,计算斐波那契数列第 n 项的常规方法是对 n-1n-2 项求和。列表理解旨在创建一个在理解过程中没有副作用的列表(除了创建单个列表)。在序列计算期间存储序列的最后 2 项是 side-effect,因此列表理解对任务本身来说是 ill-suited。

解决这个问题的一个安全方法是制作一个可以传递给列表理解的闭包生成器(本质上是一个具有一些相关私有状态的生成器),这样列表理解就不必担心什么的细节正在存储:

def fib_generator(n):

    def fib_n_generator():
        last = 1
        curr = 1

        if n == 0:
            return

        yield last
        if n == 1:
            return

        yield curr
        if n == 2:
            return

        ii = 2
        while ii < n:
            next = curr + last
            yield next
            last = curr
            curr = next
            ii += 1

    return fib_n_generator()

fib = [xx for xx in fib_generator(10)]
print(fib)

如果您知道您将需要多少个系列项,那么您可以紧凑地编写代码,而无需像这样的列表理解。

def Fibonacci(n):
    f0, f1 = 1, 1
    for _ in range(n):
        yield f0
        f0, f1 = f1, f0+f1

fibs = list(Fibonacci(10))
print (fibs)

如果你想要一些不确定数量的术语,那么你可以使用它,它非常相似。

def Fibonacci():
    f0, f1 = 1, 1
    while True:
        yield f0
        f0, f1 = f1, f0+f1

fibs = []
for f in Fibonacci():
    fibs.append(f)
    if f>100:
        break
print (fibs)

当您需要一个可能无限的项目集合时,您或许应该考虑使用一个或多个 yield 语句的 function 或一个生成器表达式。我很想用生成器表达式生成斐波那契数列,但显然不能。

我们可以将它写成一个干净的 Python 列表理解(或生成器),使用它与黄金比例的关系:

>>> series = [int((((1 + 5**0.5) / 2)**n - ((1 - 5**0.5) / 2)**n) / 5**0.5) for n in range(1, 21)]
>>> series
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765]
>>> 

或者更好一点:

>>> square_root_of_five = 5**0.5
>>> Phi = (1 + square_root_of_five) / 2
>>> phi = (1 - square_root_of_five) / 2
>>> 
>>> series = [int((Phi**n - phi**n) / square_root_of_five) for n in range(1, 21)]
>>> series
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765]

使用列表理解:

n = int(input())
fibonacci_list = [0,1]
[fibonacci_list.append(fibonacci_list[k-1]+fibonacci_list[k-2]) for k in range(2,n)]

if n<=0:
   print('+ve numbers only')
elif n == 1:
   fibonacci_list = [fibonacci_list[0]]
   print(fibonacci_list)
else:
   print(fibonacci_list)

也许这是解决这个问题的可行方案...

使用赋值表达式(python >= 3.8):

s = [0, 1]
s += [(s := [s[1], s[0] + s[1]]) and s[1] for k in range(10)]

print (s)
# [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]

斐波那契数列的列表理解,基于显式公式 1:

[int((0.5+5**0.5/2)**n/5**0.5+0.5) for n in range(21)]

这是一个单行列表理解解决方案,它避免了嵌套 ternary operators and the walrus operator (so needs Python 3.8), and also avoids the rapid onset of overflow problems that the 的单独初始化步骤,可以为您提供(及其 **n 组件):

[
    0 if not i else
        (x := [0, 1]) and 1 if i == 1 else
            not x.append(x[-2] + x[-1]) and x[-1]
    for i in range(10)
]

给出:

[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

这比 生成最多 N 个值的速度更快。但是,如果您不想要所有值,那么显式形式可能会快得多,但它确实如此在 1000 到 2000 之间的某些 N 中溢出:

n = 2000
int((((1 + 5**0.5) / 2)**n - ((1 - 5**0.5) / 2)**n) / 5**0.5)

给我:

OverflowError: (34, 'Numerical result out of range')

而“将最后两个值相加”的方法可以为较大的 N 生成更高的值。在我的机器上,在我 运行 内存不足之前,我可以继续前进直到 300000 和 400000 之间的某个 N。

感谢 Jonathan Gregory 带领我采用这种方法。

来自 Python 单行本,作者 Christian Mayer。

n = 10
x = [0,1]
fibs = x[0:2] + [x.append(x[-1] + x[-2]) or x[-1] for i in range(n-2)]
print(fibs)
# [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

答案是你可以在没有赋值运算符的情况下使用列表理解来做到这一点(即使在Python 2中也可以)。

我是这样做的:

def Phi(number:int):
n = [1,1]
[n.append(n[i-2]+n[i-1])for i in range(2,number)]
return n