使用Python列表推导计算列表中的正整数元素

时间:2010-05-24 20:26:22

标签: python list sum integer list-comprehension

我有一个整数列表,我需要计算它们中有多少是> 0
我目前正在使用列表理解,如下所示:

sum([1 for x in frequencies if x > 0])

这似乎是一种体面的理解,但我并不喜欢“1”;这看起来像是一个神奇的数字。有没有更多的Python方法来做到这一点?

7 个答案:

答案 0 :(得分:76)

如果要减少内存量,可以避免使用生成器生成临时列表:

sum(x > 0 for x in frequencies)

这是有效的,因为boolint的子类:

>>> isinstance(True,int)
True

True的值为1:

>>> True==1
True

然而,正如Joe Golton在评论中指出的那样,这个解决方案并不是很快。如果您有足够的内存来使用中间临时列表,那么sth's solution可能会更快。以下是比较各种解决方案的一些时间:

>>> frequencies = [random.randint(0,2) for i in range(10**5)]

>>> %timeit len([x for x in frequencies if x > 0])   # sth
100 loops, best of 3: 3.93 ms per loop

>>> %timeit sum([1 for x in frequencies if x > 0])
100 loops, best of 3: 4.45 ms per loop

>>> %timeit sum(1 for x in frequencies if x > 0)
100 loops, best of 3: 6.17 ms per loop

>>> %timeit sum(x > 0 for x in frequencies)
100 loops, best of 3: 8.57 ms per loop

请注意,timeit结果可能因Python,OS或硬件的版本而异。

当然,如果你在一大堆数字上做数学,你可能应该使用NumPy:

>>> frequencies = np.random.randint(3, size=10**5)
>>> %timeit (frequencies > 0).sum()
1000 loops, best of 3: 669 us per loop

NumPy数组比等效的Python列表需要更少的内存,并且计算的执行速度可以比任何纯Python解决方案快得多。

答案 1 :(得分:23)

稍微多一点Pythonic的方式就是使用生成器:

sum(1 for x in frequencies if x > 0)

这可以避免在调用sum()之前生成整个列表。

答案 2 :(得分:9)

您可以在已过滤的列表中使用len()

len([x for x in frequencies if x > 0])

答案 3 :(得分:4)

这样可行,但将bool添加为int可能会很危险。请把这个代码带上一粒盐(可维护性先行):

sum(k>0 for k in x)

答案 4 :(得分:1)

如果数组只包含元素> = 0(即所有元素都是0或正整数),那么你可以只计算零并从数组的长度中减去这个数字:

len(arr) - arr.count(0)

答案 5 :(得分:0)

这个怎么样?

reduce(lambda x, y: x+1 if y > 0 else x, frequencies)

编辑: 灵感来自@~unutbu的接受答案:

reduce(lambda x, y: x + (y > 0), frequencies)

答案 6 :(得分:0)

我想指出,所有这些都适用于列表。如果我们有一个 numpy 数组, 有些解决方案至少能快 40 倍......

总结给出的所有解决方案并测试效率,再加上一些(必须修改reduce代码才能在Python 3中运行它),注意最后一个答案是micros,而不是millis: enter image description here

可复制粘贴格式的代码:

import random
import functools
frequencies = [random.randint(0,2) for i in range(10**5)]
from collections import Counter
import numpy as np

%timeit len([x for x in frequencies if x > 0])   # sth
%timeit sum([1 for x in frequencies if x > 0])
%timeit sum(1 for x in frequencies if x > 0)
%timeit sum(x > 0 for x in frequencies)
%timeit functools.reduce(lambda x, y: x + (y > 0), frequencies)
%timeit Counter(frequencies)

#'-------Numpy-----------------------')
%timeit ((np.array(frequencies))>0).sum()
npf=np.array(frequencies)
#'-------Numpy without conversion ---')
%timeit (npf>0).sum()