web-dev-qa-db-ja.com

Python

これが以前に尋ねられたかどうかはわかりませんが、明白な答えを見つけることができませんでした。特定の値に等しいリスト内の要素の数を数えようとしています。問題は、これらの要素が組み込み型ではないことです。だから私が持っているなら

class A:
    def __init__(self, a, b):
        self.a = a
        self.b = b

stuff = []
for i in range(1,10):
    stuff.append(A(i/2, i%2))

ここで、フィールドb = 1のリスト要素の数を求めます。2つの解決策を考え出しました。

print [e.b for e in stuff].count(1)

そして

print len([e for e in stuff if e.b == 1])

どちらが最良の方法ですか?より良い代替手段はありますか? count()メソッドはキーを受け入れないようです(少なくともPythonバージョン2.5.1では)。

どうもありがとう!

25
nicolaum
sum(x.b == 1 for x in L)

ブール値(x.b == 1などの比較の結果)もintであり、値はFalseの場合は0Trueの場合は1であるため、合計などの演算は問題なく機能します。

これは最も単純なコードですが、おそらく最も高速ではありません(timeitだけが確実に教えてくれます;-)。考慮してください(コマンドラインにうまく適合するように簡略化されたケースですが、同等です):

$ py26 -mtimeit -s'L=[1,2,1,3,1]*100' 'len([x for x in L if x==1])'
10000 loops, best of 3: 56.6 usec per loop
$ py26 -mtimeit -s'L=[1,2,1,3,1]*100' 'sum(x==1 for x in L)'
10000 loops, best of 3: 87.7 usec per loop

したがって、この場合、余分な一時リストを生成してその長さをチェックする「メモリを浪費する」アプローチは、実際には、私が好む、より単純で、より短く、メモリを節約するアプローチよりも確実に高速です。もちろん、リスト値の他の組み合わせ、Python実装、この高速化に「投資」するためのメモリの可用性など)は、正確なパフォーマンスに影響を与える可能性があります。

43
Alex Martelli
print sum(1 for e in L if e.b == 1)
15
Roger Pate

リストを1回だけループするので、2番目のものをお勧めします。

count()を使用する場合は、リストを1回ループしてb値を取得してから、もう一度ループして、どれだけが1に等しいかを確認します。

きちんとした方法でreduce()を使用できます:

_reduce(lambda x,y: x + (1 if y.b == 1 else 0),list,0)
_

ドキュメント は、reduce()が次のことを行うことを示しています。

Iterableを単一の値に減らすために、2つの引数の関数を左から右にiterableの項目に累積的に適用します。

したがって、リストアイテムのlambda属性が1の場合にのみ、累積値を1つ追加するbを定義します。

2
Dave Webb

reduceの詳細を非表示にするには、count関数を定義します。

def count(condition, stuff):
    return reduce(lambda s, x: \
                  s + (1 if condition(x) else 0), stuff, 0)

次に、カウントの条件を指定して使用できます。

n = count(lambda i: i.b, stuff)
0
Calvin