这是Project Euler问题2:
Fibonacci序列中的每个新术语都是通过添加 前两个任期。从1和2开始,前10个术语将 是:
1,2,3,5,8,13,21,34,55,89,......
考虑Fibonacci序列中的值,而不是 超过四百万,找到偶数值的总和。
一种可能的直接方法是:
def fib_even(n):
previous, current = 0, 1
sum_fib = 0
while current <= n:
previous, current = current, previous + current
if current % 2 == 0:
sum_fib += current
return sum_fib
然后我尝试用一种“纯”生成器以某种功能方式进行:
def fibonacci_generator():
curr_fib, next_fib = 0, 1
while True:
yield curr_fib
curr_fib, next_fib = next_fib, curr_fib + next_fib
print(sum(itertools.filterfalse(lambda x: x % 2 == 0, itertools.takewhile(lambda x: x < n, fibonacci_generator()))))
这个版本效率低下,因为多次完成相同的工作(屈服)。
我的问题:生成Fibonacci数字的功能方法是什么,直到达到某个限制并同时过滤奇数。 (不改变第二版中的发电机。)
作为参考,十亿的第一个版本timeit给出:
100000 loops, best of 3: 10 µs per loop
十亿的第二个版本时间表给出了:
10000 loops, best of 3: 28.8 µs per loop
答案 0 :(得分:1)
在生成器中进行过滤会更快:
def my_fibonacci_generator():
curr_fib, next_fib = 0, 1
while True:
if not curr_fib % 2:
yield curr_fib
curr_fib, next_fib = next_fib, curr_fib + next_fib
n = 4000000
sum(takewhile(lambda i: i < n, my_fibonacci_generator())
在不到一半的时间内运行:
In [10]: timeit (sum(filterfalse(lambda x: x % 2 == 0, takewhile(lambda x: x < n, fibonacci_generator()))))
100000 loops, best of 3: 16.1 µs per loop
In [11]: timeit sum(takewhile(lambda i: i < n, my_fibonacci_generator()))
100000 loops, best of 3: 7.65 µs per loop
In [12]: sum(filterfalse(lambda x: x % 2 == 0, takewhile(lambda x: x < n, fibonacci_generator())))
Out[12]: 4613732
In [13]: sum(takewhile(lambda i: i < n, my_fibonacci_generator()))
Out[13]: 4613732
lambda的成本正在减慢你自己的功能。除非你可以使用内置行map(operator.add
而不是lambda等效,否则功能方法总会受到影响。
在不修改的情况下接近相同运行时的唯一方法是首先执行过滤:
In [57]: timeit sum(takewhile(lambda x: x < n, filter(lambda x: x & 1, fibonacci_generator())))
100000 loops, best of 3: 9.93 µs per loop