【问题标题】:How can I create the fibonacci series using a list comprehension?如何使用列表推导创建斐波那契数列?
【发布时间】:2017-07-11 06:15:33
【问题描述】:

我是 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

让我知道是否甚至可以使用列表推导生成这样的系列。

【问题讨论】:

  • 你不能那样做,因为 list comprehension 在添加到 series...之前先被评估过。
  • reduce 是斐波那契数列的更好选择,因为迭代 X 的输入取决于迭代 X -1 的输出

标签: python list-comprehension fibonacci


【解决方案1】:

你不能那样做:列表推导首先被求值,然后该列表被添加到series。所以基本上它就像你会写的那样:

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

不过,您可以通过使用 list comprehension 作为一种强制副作用 来解决这个问题,例如:

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

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

【讨论】:

  • Using assignment expressions in python3.8,您可以绕过带有副作用的列表推导来创建一个新的 fib 数字列表。是否比使用副作用更好(正如您在此处所做的那样)是值得商榷的。
  • 这将创建另一个列表。我宁愿使用普通函数。
【解决方案2】:

以 Willem van Onsem 所说的话为基础:

如您所知,计算斐波那契数列第 n 项的传统方法是将 n-1n-2 项相加。列表推导旨在创建一个在推导期间没有副作用的列表(除了创建单个列表)。在计算序列期间存储序列的最后 2 项是一种副作用,因此列表推导本身不适合该任务。

解决这个问题的一种安全方法是创建一个闭包生成器(本质上是一个具有一些相关私有状态的生成器),它可以传递给列表推导式,这样列表推导式就不必担心存储内容的细节:

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)

【讨论】:

  • 感谢Storing the last 2 terms of the sequence during calculation of the sequence is a side-effect, therefore a list comprehension is ill-suited to the task on its own 第一段中的解释。
  • 但是,即使花费了 15 分钟以上,我也无法理解在上面的代码 sn-p 中使用 yield 有什么好处。如果fib_generator(n) 是一个没有生成器的函数,fib = [xx for xx in fib_generator(10)] 仍然会被调用。
  • 产量至关重要,否则它不是生成器。没有 yield fib_n_generator() 只会返回一件事,而不是可迭代的事物。不过,我本可以让我的答案更简单:我不需要嵌套函数,所以它应该看起来像比尔贝尔的答案(这就是为什么他有更多的支持 ;-))。我也可以重写它以返回列表而不是生成器,但这会破坏使用生成器的主要目的,即避免不必要的 RAM 使用。
【解决方案3】:

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

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 或生成器表达式。我希望能够使用生成器表达式制作斐波那契数,但显然不能。

【讨论】:

    【解决方案4】:

    我们可以使用它与黄金比例的关系将它写成一个干净的 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]
    

    【讨论】:

      【解决方案5】:

      使用列表理解:

      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)
      

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

      【讨论】:

        【解决方案6】:

        使用赋值表达式(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]
        

        【讨论】:

          【解决方案7】:

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

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

          【讨论】:

            【解决方案8】:

            这是一个单行列表理解解决方案,它避免了嵌套 ternary operatorswalrus operator 的单独初始化步骤(因此需要 Python 3.8),并且还避免了 explicit form 可以给出的快速发生的溢出问题你(带有**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]
            

            这比 explicit form 生成最多 N 的所有值要快。但是,如果您不想要所有值,那么显式形式可能会快得多,但它确实会遭受溢出一些 N 在 1000 到 2000 之间:

            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)带领我走上这条路。

            【讨论】:

              【解决方案9】:

              来自 Christian Mayer 的 Python One-Liners

              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 中也可以使用)。

              【讨论】:

              • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
              【解决方案10】:

              我是这样做的:

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

              【讨论】:

                猜你喜欢
                • 2023-03-09
                • 2013-04-29
                • 1970-01-01
                • 2014-08-20
                • 2013-10-04
                • 2015-06-05
                • 1970-01-01
                相关资源
                最近更新 更多