2

我在使用 itertools.count 函数时遇到了一些问题,我不太明白它的作用。我希望下面的代码能够完成Project Euler 问题 2

我知道我可以用一个简单的while循环来写这个,但是有没有办法用列表理解来做到这一点?这段代码只是冻结,因为我猜它会随着 count() 变得无穷大。我希望它会在 x > MAX 之后停止,但我知道这不会发生。有没有办法在下面的生成器表达式中停止计数?

def fib(n):
    if (n <= 1): return 1
    else: return fib(n-1) + fib(n-2)


MAX = 4000000

infiniteFib = (fib(x) for x in count())

s = (x for x in infiniteFib if x < MAX and x % 2 == 0)

print sum(s)
4

5 回答 5

7

你可以使用takewhile

>>> from itertools import count, takewhile, imap
>>> sum(x for x in takewhile(lambda x: x < 4000000, imap(fib, count())) if x % 2 == 0)
4613732
于 2012-12-10T23:27:51.060 回答
5

我们只需要告诉infiniteFib生成器何时停止生成元素。itertools提供了许多有用的方法来帮助解决这个问题:

less_than_max = itertools.takewhile(lambda x: x<MAX, infiniteFib))
even = itertools.ifilter(lambda x: x%2==0, less_than_max)
print sum(even)

我们得到一个生成器,用于生成由 产生的所有数字infiniteFib,直到返回的数字大于MAX。然后我们过滤那个生成器,只选择偶数。最后我们可以总结结果。

于 2012-12-10T23:28:58.147 回答
3

怎么样:

def fib():
    a, b = 1, 1
    while True:
        yield b
        a, b = b, a+b

sum(f for f in itertools.takewhile(functools.partial(operator.ge, 4000000), fib()) if f % 2 == 0)

或者,将奇偶校验推入生成器:

def even_fib():
    a, b = 1, 1
    while True:
        if b % 2 == 0: yield b
        a, b = b, a+b

sum(itertools.takewhile(functools.partial(operator.ge, 4000000), even_fib()))
于 2012-12-10T23:33:08.870 回答
0

是的,count()只是继续前进,这不是你想要的。列表推导/迭代器表达式没有灵活的退出条件(但请参阅@DSM 的解决方案使用takewhile)。

我更喜欢只使用while.

这是我对欧拉 2 的旧答案:

def SumEvenFibonacci(limit):
        x = y = 1
        sum = 0
        while (sum <= limit):
                sum += (x + y)
                x, y = x + 2 * y, 2 * x + 3 * y
        return sum

ce = SumEvenFibonacci(4000000)
print ce
于 2012-12-10T23:20:31.350 回答
0

这是另一个使用takewhile,但非递归的解决方案。由于递归解决方案需要fib为每个 n 计算所有小于 n 的 s,因此速度非常慢。

def fib_gen(only_even=False):
    one = 1
    if not only_even:
        yield one
    two = 1
    if not only_even:
        yield two
    while True:
        next = one + two
        one = two
        two = next
        if only_even:
            if next % 2 == 0:
                yield next
        else:
            yield next

list(itertools.takewhile(lambda x: x < 4000000, fib_gen()))
于 2012-12-10T23:33:11.213 回答