2016-02-24 10 views
5

整数のリストが与えられた場合、特定の範囲内にいくつの要素が含まれているかを計算する最もPythonic /最良の方法は何ですか?Python:条件の場合のリスト内の要素の数のカウント

私はそれを行うための2つの方法研究とが見つかりました:

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

か:

(大きい方のリストのための)短い時間/メモリを使用する方法
>>> x = [10, 60, 20, 66, 79, 5] 
>>> sum(1 for i in x if 60 < i < 70) 
1 

と理由を?それとも別の方法が優れている...あなたは

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

を提示した具体的な事例では

+0

あなたは実際に*リストが必要ですか?そうでない場合、第2のバージョンはそれを作成することを避ける。 – jonrsharpe

+0

ほとんどのpythonicは、時間/メモリが少ないことを意味するわけではありませんが、あなたは両方の質問について質問します。あなたは、最も有色であるか最も効率的であるかを知りたいですか? –

+0

また、if i in range(61、70) 'を使用することもできます。 –

答えて

2

はジェネレータ式は、より多くのメモリ効率的です。

リストを作成し、それの長さを取得するには、(後者は非常に高速な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 
4

は実際にブランドの新しいリストを生成し、そのlenをとります。逆に、

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

あなたがsumを取るその上generator expressionです。

関連する項目が十分に多い場合は、2番目のバージョンがより効率的になります(特にメモリの点で)。あなたは余分なリストを作成する必要はありませんので、


タイミング

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 
+0

ジェネレータに与えるスピードの優位性について質問します。私のタイミングは発電機をより速く再現することはできません。リストバージョンでは、追加する必要はありません。長さを取得するだけです。 – timgeb

+0

@timgebリストバージョンでは、ガベージコレクションが役割を果たすことがあります。 –

+0

@FrerichRaabeそれは良い点です – timgeb

2

あなたは簡単に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 

しかし、できるだけ速いと思われるのは、可能であれば最初にリストを持たないことです。 a 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 
関連する問題