100

假设我有一个包含大量项目的列表,

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

是否有任何功能样式的方法来获取满足条件的项目数而不生成临时列表?

4

5 回答 5

124

您可以使用生成器表达式

>>> 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
于 2013-03-13T00:54:15.203 回答
29

您需要生成器理解而不是此处的列表。

例如,

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

这种技术很酷的一点是,您可以在代码中指定概念上单独的步骤,而无需强制评估和存储在内存中,直到评估最终结果。

于 2013-03-13T00:53:58.810 回答
11

reduce如果您更喜欢函数式编程,这也可以使用

reduce(lambda count, i: count + my_condition(i), l, 0)

这样你只做 1 遍并且不会生成中间列表。

于 2015-09-23T15:20:30.513 回答
9

您可以执行以下操作:

l = [1,2,3,4,5,..]
count = sum(1 for i in l if my_condition(i))

它只是为满足条件的每个元素加 1。

于 2013-03-13T00:58:07.933 回答
2
from itertools import imap
sum(imap(my_condition, l))
于 2013-03-13T00:56:27.027 回答