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

Question:

I am new to python, and I was wondering if I could generate the fibonacci series using python’s list comprehension feature. I don’t know how list comprehensions are implemented.
I tried the following (the intention was to generate the first five fibonacci numbers):

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

This piece of code throws the error: IndexError: list index out of range.

Let me know if it is even possible to generate such a series using a list comprehension.

Asked By: Thenavats

||

Answers:

You cannot do it like that: the list comprehension is evaluated first, and then that list is added to series. So basically it would be like you would have written:

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

You can however solve this by using list comprehension as a way to force side effects, like for instance:

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

Note that we here do not add the result to series. The list comprehension is only used such that .append is called on series. However some consider list comprehensions with side effects rather error prone: it is not very declarative and tends to introduce bugs if not done carefully.

Answered By: Willem Van Onsem

To build on what Willem van Onsem said:

The conventional way to calculate the nth term of the fibonacci sequence is to sum the n-1 and n-2 terms, as you’re aware. A list comprehension is designed to create a list with no side effects during the comprehension (apart from the creation of the single list). 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.

A safe way around this would be to make a closure generator (essentially a generator with some associated private state) that can be passed to the list comprehension such that the list comprehension does not have to worry about the details of what’s being stored:

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)
Answered By: daphtdazz

If you know how many terms of the series you will need then you can write the code compactly without a list comprehension like this.

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

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

If you want some indefinite number of terms then you could use this, which is very similar.

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)

When you need a potentially infinite collection of items you should perhaps consider either a function with one or more yield statements or a generator expression. I’d love to be able to make Fibonacci numbers with a generator expression but apparently one can’t.

Answered By: Bill Bell

We could write it as a clean Python list comprehension (or generator) using it’s relationship to the golden ratio:

>>> 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]
>>> 

or a little more nicely as:

>>> 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]
Answered By: cdlane

Using List comprehension :

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)

maybe it’s a feasible solution for this problem…

Answered By: nikhil_2017

Using Assignment Expression (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]
Answered By: cs95

List comprehension of the fibonacci serie, based on the explicit formula 1:

[int((0.5+5**0.5/2)**n/5**0.5+0.5) for n in range(21)]
Answered By: Ziur Olpa

Here’s a one-line list comprehension solution that avoids the separate initialization step with nested ternary operators and the walrus operator (so needs Python 3.8), and also avoids the rapid onset of overflow problems that the explicit form can give you (with its **n component):

[
    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)
]

Gives:

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

This is faster than the explicit form for generating all of the values up to N. If, however, you don’t want all of the values then the explicit form could be much faster, but it does suffer from overflow for some N between 1000 and 2000:

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

gives for me:

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

whereas the "adding the last two values" approach can generate higher values for larger N. On my machine, I can keep going until some N between 300000 and 400000 before I run out of memory.

Thanks to Jonathan Gregory for leading me most of the way to this approach.

Answered By: dhassell

From Python One-Liners by 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]

The answer is you can do this with a list comprehension without the assignment operator (works even in Python 2).

Answered By: MSha

I did it this way:

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

Simplification of @dhassel version (requires python 3.8 or later)

series = [i0 := 0, i1 := 1]+[i1 := i0 + (i0 := i1) for j in range(2, 5)]

One can also be written as a generator expression, but it’s a bit tricky because for some reason, the obvious answer: fibo = (v for g in ((i0 := 0, i1 := 1), (i1 := i0 + (i0 := i1) for j in range(2,10))) for v in g) doesn’t work (I do not exclude a bug). However, it is OK if you get the subgenerators list outside :

glist = ((i0 := 0, i1 := 1), (i1 := i0 + (i0 := i1) for j in range(2, 5)))
fibo = (v for g in glist for v in g)
Answered By: Camion
# Get a number from the user.
number = int(input("enter a number"))

# Create a empty list
mylist=[] 

# create list comprehension following fibonaci series
[mylist.append(0)  if n==0 else mylist.append(1)  if n==1 else mylist.append(mylist[-2]+mylist[-1]) for n in range(number+1)]

print(mylist)  
Answered By: arshewin lal