Python itertools:组合谓词

时间:2015-12-17 16:57:26

标签: python python-3.x functional-programming

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

1 个答案:

答案 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