我在使用itertools.count函数时遇到了一些麻烦,我不太明白它的作用。我希望下面的代码能够完成Project Euler problem 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)
答案 0 :(得分: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
答案 1 :(得分: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
。然后我们过滤那个生成器,只选择偶数。最后我们可以总结一下结果。
答案 2 :(得分: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()))
答案 3 :(得分:0)
是的,count()
只是继续前进,这不是你想要的。列表推导/迭代器表达式没有灵活的退出条件(但请参阅使用takewhile
的@ DSM解决方案)。
我更喜欢使用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
答案 4 :(得分:0)
这是使用takewhile
的另一种解决方案,但非递归。由于递归解决方案需要为每个n计算小于n的所有fib
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()))