假设我有一个包含大量项目的列表,
l = [ 1, 4, 6, 30, 2, ... ]
我想获取该列表中满足特定条件的项目数。我的第一个想法是:
count = len([i for i in l if my_condition(l)])
但是如果过滤后的列表也有大量的项目,我认为 为过滤结果创建一个新列表只是浪费内存。为了效率,恕我直言,上面的调用不能比:
count = 0
for i in l:
if my_condition(l):
count += 1
是否有任何函数式方法可以获取满足条件的项目数而不生成临时列表?
您可以使用生成器表达式:
>>> l = [1, 3, 7, 2, 6, 8, 10]
>>> sum(1 for i in l if i % 4 == 3)
2
甚至
>>> sum(i % 4 == 3 for i in l)
2
它使用了
True == 1
和 False == 0
这一事实。
或者,您可以使用
itertools.imap
(python 2) 或简单地使用 map
(python 3):
>>> def my_condition(x):
... return x % 4 == 3
...
>>> sum(map(my_condition, l))
2
您需要的是 生成器理解,而不是这里的列表。
例如,
l = [1, 4, 6, 7, 30, 2]
def my_condition(x):
return x > 5 and x < 20
print sum(1 for x in l if my_condition(x))
# -> 2
print sum(1 for x in range(1000000) if my_condition(x))
# -> 14
或者使用
itertools.imap
(尽管我认为显式列表和生成器表达式看起来更Pythonic)。
请注意,虽然从
sum
示例中并不明显,但您可以很好地编写生成器推导式。例如,
inputs = xrange(1000000) # In Python 3 and above, use range instead of xrange
odds = (x for x in inputs if x % 2) # Pick odd numbers
sq_inc = (x**2 + 1 for x in odds) # Square and add one
print sum(x/2 for x in sq_inc) # Actually evaluate each one
# -> 83333333333500000
此技术的酷之处在于,您可以在代码中指定概念上独立的步骤,而无需强制评估并存储在内存中,直到评估最终结果为止。
如果您喜欢函数式编程,也可以使用
reduce
来完成
reduce(lambda count, i: count + my_condition(i), l, 0)
这样您只需执行 1 遍,并且不会生成中间列表。
你可以这样做:
l = [1,2,3,4,5,..]
count = sum(1 for i in l if my_condition(i))
它只是为每个满足条件的元素加 1。
from itertools import imap
sum(imap(my_condition, l))