web-dev-qa-db-ja.com

Pythonリスト内包表記によるリスト内の正の整数要素のカウント

整数のリストがあり、それらの数が> 0であるかを数える必要があります。
私は現在、次のようなリスト内包表記でそれをやっています:

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

それはまともな理解のように思えますが、私は本当に「1」が好きではありません。ちょっとしたマジックナンバーのようです。これを行うためのよりPython的な方法はありますか?

44
fairfieldt

メモリの量を減らしたい場合は、ジェネレーターを使用して一時リストを生成しないようにすることができます。

sum(x > 0 for x in frequencies)

これは、boolintのサブクラスであるため機能します。

>>> isinstance(True,int)
True

Trueの値は1です。

>>> True==1
True

ただし、Joe Goltonがコメントで指摘しているように、このソリューションはそれほど高速ではありません。中間の一時リストを使用するのに十分なメモリがある場合は、 sthの解決策 の方が高速です。さまざまなソリューションを比較するタイミングを次に示します。

>>> 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ソリューションよりもはるかに高速に計算を実行できます。

76
unutbu

もう少しPython的な方法は、代わりにジェネレーターを使用することです。

_sum(1 for x in frequencies if x > 0)
_

これにより、sum()を呼び出す前にリスト全体を生成することを回避できます。

23
Greg Hewgill

フィルタリングされたリストでlen()を使用できます。

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

これは機能しますが、boolsをintsとして追加すると危険です。このコードを一粒ずつ取ってください(保守性が最初になります)。

sum(k>0 for k in x)
4
Escualo

配列に0以上の要素のみが含まれる場合(つまり、すべての要素が0または正の整数)、ゼロをカウントし、配列の長さからこの数値を減算することができます。

len(arr) - arr.count(0)
1
ben_nuttall

これはどう?

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

編集:@〜unutbuから受け入れられた答えからインスピレーションを得て:

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

0
Peter Jaric