膨大な数のアイテムのリストがあると仮定します。
l = [ 1, 4, 6, 30, 2, ... ]
そのリストからアイテムの数を取得したいのですが、アイテムは特定の条件を満たす必要があります。私の最初の考えは:
count = len([i for i in l if my_condition(l)])
しかし、my_condition()フィルタリングリストにも多数のアイテムがある場合、フィルタリング結果の新しいリストを作成することは、メモリの浪費にすぎないと考えます。効率のために、私見では、上記の呼び出しは以下よりも優れていません:
count = 0
for i in l:
if my_condition(l):
count += 1
一時的なリストを生成せずに特定の条件を満たすアイテムの数を取得するための機能的なスタイルの方法はありますか?
前もって感謝します。
ジェネレータ式 を使用できます。
_>>> l = [1, 3, 7, 2, 6, 8, 10]
>>> sum(1 for i in l if i % 4 == 3)
2
_
あるいは
_>>> sum(i % 4 == 3 for i in l)
2
_
int(True) == 1
という事実を使用しています。
または、_itertools.imap
_(python 2)または単にmap
(python 3)を使用できます。
_>>> def my_condition(x):
... return x % 4 == 3
...
>>> sum(map(my_condition, l))
2
_
ここではリストではなく generator comprehension が必要です。
例えば、
l = [1, 4, 6, 7, 30, 2]
def my_condition(x):
return x > 5 and x < 20
print sum(1 for x in l if my_condition(x))
# -> 2
print sum(1 for x in range(1000000) if my_condition(x))
# -> 14
またはitertools.imap
を使用します(ただし、明示的なリストとジェネレーター式はややPythonyに見えると思いますが)。
sum
の例からは明らかではありませんが、ジェネレーターの内包表記をうまく構成できることに注意してください。例えば、
inputs = xrange(1000000) # In Python 3 and above, use range instead of xrange
odds = (x for x in inputs if x % 2) # Pick odd numbers
sq_inc = (x**2 + 1 for x in odds) # Square and add one
print sum(x/2 for x in sq_inc) # Actually evaluate each one
# -> 83333333333500000
この手法の素晴らしい点は、最終結果が評価されるまで評価とメモリへの保存を強制することなく、コード内で概念的に個別のステップを指定できることです。
次のようなことができます:
l = [1,2,3,4,5,..]
count = sum(1 for i in l if my_condition(i))
条件を満たす各要素ごとに1を追加します。
関数型プログラミングを好む場合は、reduce
を使用してこれを行うこともできます。
reduce(lambda count, i: count + my_condition(i), l, 0)
この方法では、1パスのみを実行し、中間リストは生成されません。
from itertools import imap
sum(imap(my_condition, l))
同様の問題があり、ジェネレーターを使用して解決しました。
また、この質問はあなたを助けることができると思います: リストのフィルタリング:リストの理解vs.ラムダ+フィルター