整数のリストがあり、それらの数が> 0であるかを数える必要があります。
私は現在、次のようなリスト内包表記でそれをやっています:
sum([1 for x in frequencies if x > 0])
それはまともな理解のように思えますが、私は本当に「1」が好きではありません。ちょっとしたマジックナンバーのようです。これを行うためのよりPython的な方法はありますか?
メモリの量を減らしたい場合は、ジェネレーターを使用して一時リストを生成しないようにすることができます。
sum(x > 0 for x in frequencies)
これは、bool
がint
のサブクラスであるため機能します。
>>> 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ソリューションよりもはるかに高速に計算を実行できます。
もう少しPython的な方法は、代わりにジェネレーターを使用することです。
_sum(1 for x in frequencies if x > 0)
_
これにより、sum()
を呼び出す前にリスト全体を生成することを回避できます。
フィルタリングされたリストでlen()
を使用できます。
len([x for x in frequencies if x > 0])
これは機能しますが、bool
sをint
sとして追加すると危険です。このコードを一粒ずつ取ってください(保守性が最初になります)。
sum(k>0 for k in x)
配列に0以上の要素のみが含まれる場合(つまり、すべての要素が0または正の整数)、ゼロをカウントし、配列の長さからこの数値を減算することができます。
len(arr) - arr.count(0)
これはどう?
reduce(lambda x, y: x+1 if y > 0 else x, frequencies)
編集:@〜unutbuから受け入れられた答えからインスピレーションを得て:
reduce(lambda x, y: x + (y > 0), frequencies)