2017-02-13 19 views
4

リスト/タプル/シーケンスをループする場合は、len(...)を使用して、ループの実行回数を推測できます。しかし、イテレータをループするときはできません。ループ実行をカウントするためのPythonイディオム

[]明確にするために更新:私はアイテムの計算を行い、同時にそれらを数えたいと思う1回限りの有限イテレータについて考えています。]

私は現在、次の例のように、明示的なカウンタ変数を使用します。

が11の文字は、 "Hello world"である ここで予想される出力がある与えられた
def some_function(some_argument): 
    pass 


some_iterator = iter("Hello world") 

count = 0 
for value in some_iterator: 
    some_function(value) 
    count += 1 

print("Looped %i times" % count) 

Looped 11 times 

私が持っていますenumerate(...)を使用してこの短い代替案を検討しましたが、わかりません:

def some_function(some_argument): 
    pass 


some_iterator = iter("Hello world") 

count = 0 # Added for special case, see note below 
for count, value in enumerate(some_iterator, start=1): 
    some_function(value) 

print("Looped %i times" % count) 

[]更新:@mataは、イテレータが空の場合、この2番目の例が最初に書かれたとおりに失敗することを発見しました。 count = 0を挿入するとこれを解決するか、for ... else ...構造を使用してこのコーナーケースを処理することができます。]

ループ内のインデックスはenumerate(...)ではありませんが、変数をループカウントに設定することはほぼ副作用です。私にとっては、これはかなり不明なので、私は明示的なインクリメントの最初のバージョンを好みます。

Python 3とPython 2の両方のコードでこれを行うPythonの方法がありますか?

+0

はい、この解決策は '列挙型です。なぜあなたはそれを「はっきりした」ものではないと考えますか?私はそれに慣れているのかどうか分かりませんが、「列挙する」はわかりやすいようです... – schwobaseggl

+3

それは...私は2番目のフォームがもっとpythonicだと言いたいと思います。まったく同じケースをカバーしていません。なぜなら、反復子にループが定義されておらず、NameErrorを取得した後に 'count'要素がなければ、' for ... else'を使うか、カウンタを初期化するからですループの前に – mata

+0

良い点@mata、イテレータが空の場合、書かれた2番目の例は失敗します。 – peterjc

答えて

1

イテレータの項目数を取得する方法はありません。このケースを考える

def gen(): 
    a = 1 
    while True: 
     yield a 
     a += 1 
f = gen() 

for value in f: 
    # do something 

このイテレーターのサイズは?イテレータは、との場合はの場合はStopIterationになります。それどころか、シーケンスを反復するとき、シーケンスはすでに存在するので、その長さを知ることができます。

どちらの方法でも問題ありません。 最高はあなたの好みによって異なります。もう1つのオプションは、使用することです

from itertools import count 
for item, counter in zip(iterator, count()): 
    # do stuff 

しかし、私はほとんどの場合、あなたの最初の伝統的なアプローチがより明確になると思います。

+0

これはなぜ私がこの質問をしているのかを説明するための良い例です - イテレータで '' len(...) ''を使うことはできないことに注意してください。しかし、あなたの答えは私の質問に答えるものではありません。これはforループでiteratorを使用していると仮定してイテレータ内の項目の数を数えるのが最善の方法です。 – peterjc

+0

@peterjc:それは不可能だと指摘しています。質問を編集しました –

+0

ありがとう - それは今より明確です。私は、「最良の」アプローチが趣味の問題になるだろうと同意します。 – peterjc

0

この問題は何ですか?あなたがそれを必要とするすべては内の項目数を数えることである場合

count = 0 # Counter is set in any case. 
for count, item in enumerate(data, start=1): 
    doSomethingTo(item) 
print "Did it %d times" % count 

:ループが1行を追加して実行しなかった場合は、定義されているカウンターでenumerateの利便性を組み合わせることができます

len(list(some_iterator)) 
+2

これは動作しますが、 'some_iterator'のすべての要素をメモリに読み込みます。 –

5

イテレータは、アイテムを何もせずに、それらのリストを作成せずに、あなたは単にそれを行うことができます。

count = sum(1 for ignored_item in data) # count a 1 for each item 
+1

このように書かれているように、これは1つのエラー(デフォルトでは '' enumerate''は '' 0''から '' count - 1''を使用します)を持っています。 – peterjc

+0

私はsumを使ってリスト圧縮トリックに精通していますが、この場合、項目で何かをする必要があります(この例では '' some_function''で表されます)。 – peterjc

+1

@peterjc:良いキャッチ、ありがとう!私は 'start = 1'で答えを更新しました。 – 9000

2

あなたはgenerato内の項目の数をカウントするもののすべてのソートを行うことができますrであるが、いずれの場合も元の発電機は無駄になる。疲れた、正確である。それがうまく空の発電機の場合を処理し、予想通りゼロを返すよう

length = sum(1 for x in gen) 
length = max(c for c, _ in enumerate(gen, 1)) 
length = len(list(gen)) 
  1. ここに示した第一の方法は、本当に素晴らしいです。
  2. 消耗したジェネレータが与えられたときに2番目のコードが例外を発生させますが、それは使い果たされてはいけないときに便利ですが、実際には実行されるので、何がうまくできなかったのかを調べることができます。
  3. genで提供されているデータが大きすぎると、このコードは多分メモリを無駄にするでしょうが、理解するのは簡単なので、誰も壁に頭を打つことを考える必要はありません。

これらはすべて有限の発電機でのみ動作します。

その上をループしながら、あなたはイテレータの「長さ」を計算したい場合は、あなたがこれを行うことができます:

length = 0 
for length, data in enumerate(gen, 1): 
    # do stuff 

さて、lengthは、発電機を生産している要素の数に等しくなります。 lengthを手動でインクリメントする必要はないことに注意してください。lengthdataはループ実行後でも有効で有効です。


EDIT:あなたは、各値のためのいくつかの機能を実行し、その戻り値を無視したい場合は(あなたが関数の引数の一つとしてリストを使って、それを扱うことができます)、あなたはこれを試すことができます。

length = sum(1 | bool(function(x)) for x in gen) 

これは、発電機の各要素にfunctionを適用しながら長さを計算します。それでも、enumerateを使用すると良いアイデアのように見えます。

+0

あなたの例では、ジェネレータ内の項目を使ってコードを実行することはできません(これは、実行するのに高価なもの、または一度の使用になる可能性があります)。しかし、あなたは "enumerate"アプローチを承認することで終わります。 – peterjc

+0

@peterjc、私は最初のソリューションの1つに関数アプリケーションを組み込む方法の例を追加しました。 – ForceBru

+0

これは、各アイテムの機能を呼び出すこととカウントを組み合わせる発明的なジェネレータの表現アプローチですが、味の問題として私は複雑すぎると感じています。私の質問の本質は、選択肢を判断することは常に主観的になることを意味します。 – peterjc

関連する問題