过滤器/地图是否等同于列表理解? 假设我有以下功能
def fib_gen():
a,b = 0,1
yield 0
yield 1
while True:
a,b = b,a+b
yield b
现在我可以使用list comprehension列出fib数:
a = fib_gen()
print [a.next() for i in range(int(sys.argv[1]))]
假设我只想列出偶数的fib数。我将使用filter / map执行以下操作:
a = fib_gen()
print filter(even, map(lambda x: a.next(), range(int(sys.argv[1]))))
如何使用列表推导得到相同的结果?
答案 0 :(得分:13)
过滤器/地图是否等同于列表理解?
是的,map(f, L)
相当于[f(x) for x in L]
。 filter(f, L)
相当于[x for x in L if f(x)]
。但是,由于具有副作用的列表推导通常很糟糕(在这里你修改了生成器的状态),你可以使用itertools
来获得更清洁的解决方案:
a = fib_gen()
a = itertools.islice(a, int(sys.argv[1]))
a = itertools.ifilter(even, a)
print list(a)
答案 1 :(得分:9)
您可以使用生成器存储中间结果,并在其上“过滤”。
fibs = (a.next() for i in whatever)
even_fibs = [num for num in fibs if num % 2 == 0]
或一行:
even_fibs = [num for num in (a.next() for i in whatever) if num % 2 == 0]
请注意,如果您想从迭代器中获取一定数量的元素,可以使用itertools.islice
代替:
from itertools import islice
fibs_max_count = int(sys.argv[1])
even_fibs = [num for num in islice(fib_gen(), fibs_max_count) if num%2 == 0]
答案 2 :(得分:6)
filter
和map
很容易转换为列表理解。
这是一个基本的例子:
[hex(n) for n in range(0, 100) if n > 20]
这相当于:
list(map(hex, filter(lambda x: x > 20, range(0, 100))))
在我看来,理解更具可读性。但是,如果条件变得非常先进,我更喜欢filter
。
所以在你的情况下:
[n for n in itertools.islice(fib_gen(), 100) if even(n)]
我在这里使用过islice
,因为序列是无限的。但是如果使用生成器表达式,它也会成为无限流:
gen = (n for n in fib_gen() if even(n))
现在您可以使用islice
print itertools.islice(gen, int(sys.argv[1]))
这避免了在理解本身中使用next
的需要。只要您不尝试评估无限序列(就像我们在列表推导中省略islice
那样),我们就可以使用您的序列。
答案 3 :(得分:1)
我不认为这适用于发电机。为了使这项工作与列表理解,你需要:
print [a.next() for i in range(int(sys.argv[1])) if even(a.next())]
返回:
[1, 3, 13, 55, 233]
问题是您需要访问列表中下一个数字的两倍,但第二个a.next()调用会使它应该执行的操作,即获取下一个数字。据我所知,不可能将带有列表推导的a.next()值存储两次。
答案 4 :(得分:1)
您可以使用以下代码:
a = fib_gen()
print [a.next() for i in range(int(sys.argv[1])) if i%3==0]
这是一个特殊情况,因为每个第三个fibbonacci数是偶数。
答案 5 :(得分:0)
您也可以始终生成均匀的fibo数字......
def evenfib():
""" Generates the even fibonacci numbers """
a, b = 2, 0
while True:
a, b = b, a+4*b
yield a