filter映射vs列表推导
filter和map是不是跟列表推导式一样的东西?
假设我有一个这样的函数:
def fib_gen():
a,b = 0,1
yield 0
yield 1
while True:
a,b = b,a+b
yield b
现在我可以用列表推导式来列出斐波那契数:
a = fib_gen()
print [a.next() for i in range(int(sys.argv[1]))]
假如我只想列出偶数的斐波那契数,我可以用filter和map这样做:
a = fib_gen()
print filter(even, map(lambda x: a.next(), range(int(sys.argv[1]))))
那我怎么用列表推导式得到一样的结果呢?
6 个回答
7
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
一样),我们就可以处理你的序列。
13
filter和map跟列表推导式是一样的吗?
是的,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)
10
你可以用生成器来存储中间结果,然后在这个结果上进行“过滤”。
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]