Python:计算if条件列表中元素的数量

时间:2016-02-24 15:16:21

标签: python

给定一个整数列表,计算一定范围内有多少元素的Pythonic /最佳方法是什么?

我研究并找到了两种方法:

428 Precondition Required

或:

>>> x = [10, 60, 20, 66, 79, 5]
>>> len([i for i in x if 60 < i < 70])
1

哪种方法使用较少的时间/内存(对于较大的列表)以及为什么?或者也许另一种方式更好......

3 个答案:

答案 0 :(得分:4)

在您提交的具体实例中

[i for i in x if 60 < i < 70]

实际上会生成一个全新的列表,然后使用其len。相反,

(1 for i in x if 60 < i < 70)

generator expression,您可以使用sum

对于足够大的相关项目,第二个版本将更有效(特别是在内存方面)。

<强>计时

x = [65] * 9999999

%%time

len([i for i in x if 60 < i < 70])

CPU times: user 724 ms, sys: 44 ms, total: 768 ms
Wall time: 768 ms
Out[7]:
9999999

%%time

sum(1 for i in x if 60 < i < 70)
CPU times: user 592 ms, sys: 0 ns, total: 592 ms
Wall time: 593 ms

答案 1 :(得分:3)

生成器表达式更有效 memory ,因为您不必创建额外的列表。

创建一个列表并获得它的长度(后者是一个非常快的O(1)操作)似乎更快比创建一个生成器并为相对较小的列表做n次添加

In [13]: x = [1]
In [14]: timeit len([i for i in x if 60 < i < 70])
10000000 loops, best of 3: 141 ns per loop
In [15]: timeit sum(1 for i in x if 60 < i < 70)
1000000 loops, best of 3: 355 ns per loop
In [16]: x = range(10)
In [17]: timeit len([i for i in x if 60 < i < 70])
1000000 loops, best of 3: 564 ns per loop
In [18]: timeit sum(1 for i in x if 60 < i < 70)
1000000 loops, best of 3: 781 ns per loop
In [19]: x = range(50)
In [20]: timeit len([i for i in x if 60 < i < 70])
100000 loops, best of 3: 2.4 µs per loop
In [21]: timeit sum(1 for i in x if 60 < i < 70)
100000 loops, best of 3: 2.62 µs per loop
In [22]: x = range(1000)
In [23]: timeit len([i for i in x if 60 < i < 70])
10000 loops, best of 3: 50.9 µs per loop
In [24]: timeit sum(1 for i in x if 60 < i < 70)
10000 loops, best of 3: 51.7 µs per loop

我尝试了各种列表,例如[65]*n,趋势不会改变。例如:

In [1]: x = [65]*1000
In [2]: timeit len([i for i in x if 60 < i < 70])
10000 loops, best of 3: 67.3 µs per loop
In [3]: timeit sum(1 for i in x if 60 < i < 70)
10000 loops, best of 3: 82.3 µs per loop

答案 2 :(得分:3)

您可以使用timeit模块轻松测试。对于您的特定示例,基于len的第一个解决方案似乎更快:

$ python --version
Python 2.7.10
$ python -m timeit -s "x = [10,60,20,66,79,5]" "len([i for i in x if 60 < i < 70])"
1000000 loops, best of 3: 0.514 usec per loop
$ python -m timeit -s "x = [10,60,20,66,79,5]" "sum(i for i in x if 60 < i < 70)"
1000000 loops, best of 3: 0.693 usec per loop

即使对于较大的列表 - 但大多数元素与谓词不匹配 - len版本似乎并不慢:

$ python -m timeit -s "x = [66] + [8] * 10000" "len([i for i in x if 60 < i < 70])"
1000 loops, best of 3: 504 usec per loop
$ python -m timeit -s "x = [66] + [8] * 10000" "sum(1 for i in x if 60 < i < 70)"
1000 loops, best of 3: 501 usec per loop

实际上,即使给定列表的大多数元素匹配(因此构造一个大结果列表以传递给len),len版本也会获胜:

$ python -m timeit -s "x = [66] + [65] * 10000" "len([i for i in x if 60 < i < 70])"
1000 loops, best of 3: 762 usec per loop
$ python -m timeit -s "x = [66] + [65] * 10000" "sum(1 for i in x if 60 < i < 70)"
1000 loops, best of 3: 935 usec per loop

然而,似乎更快的是,如果可能的话,首先没有列表,而是保持例如一个collections.Counter。例如。对于100000个元素,我得到:

$ python -m timeit -s "import collections; x = [66] + [65] * 100000" "len([i for i in x if 60 < i < 70])"
100 loops, best of 3: 8.11 msec per loop
$ python -m timeit -s "import collections; x = [66] + [65] * 100000; d = collections.Counter(x)" "sum(v for k,v in d.items() if 60 < k < 70)"
1000000 loops, best of 3: 0.761 usec per loop