2012-12-10 32 views
2

我在itertools.count函數中遇到了一些麻煩,我不太明白它的作用。我期望下面的代碼完成Project Euler problem 2Python求和itertools.count?

我知道我可以用一個簡單的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) 
+2

無論哪種方式,這是計算斐波那契數值的一個*非常*低效的函數。過了30多歲的任何事情都會在我的機器上永久返回,而且這是相當健壯的。 – NullUserException

+2

我有記憶的實際功能,所以它不是壞事。 –

+1

哦,繼續吧。 – NullUserException

回答

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。然後我們過濾該生成器,只選擇偶數。最後我們可以總結結果。

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 
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 
+0

+1良好的通話時間。我會記住的。 – jimhark

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())) 
+0

我有同樣的想法,但你做得更加優雅。 – Marius

0

下面是使用takewhile另一種解決方案,但非遞歸。由於遞歸解決方案需要計算每個n小於n的所有fib,因此速度很慢。

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()))