web-dev-qa-db-ja.com

pythonループ内でイテレータを任意にインクリメントする

私はおそらくこれを間違った方法で行っていますが、Pythonでこれをどのように扱うのか疑問に思っていました。

最初にいくつかのCコード:

int i;

for(i=0;i<100;i++){
  if(i == 50)
    i = i + 10;
  printf("%i\n", i);
}

わかりましたので、私たちは50年代を見ることはありません...

私の質問は、どのようにPythonで似たようなことをすることができますか?例えば:

for line in cdata.split('\n'):
  if exp.match(line):
    #increment the position of the iterator by 5?
    pass
  print line

Pythonでの経験が限られているため、1つのソリューションしかなく、カウンターとifステートメントを導入します。 exp.match(line)がtrueになった後、カウンターが5に達するまでループを中断します。

これを行うにはより良い方法が必要です。できれば、別のモジュールをインポートする必要はありません。

前もって感謝します!

47
jr0d

Python itertools と呼ばれる素晴らしいパッケージがあります。

しかし、その前に、反復プロトコルがPythonでどのように実装されているかを説明するのに役立ちます。コンテナを反復処理する場合は、 __iter__() クラスメソッドを指定します。このメソッドは iterator type を提供します。 「Pythonの「for」ステートメントを理解する」 は、for-inステートメントは、実際にはPythonで動作し、イテレータタイプがどのように動作するかについての素晴らしい概要を提供します。

以下をご覧ください。

>>> sequence = [1, 2, 3, 4, 5]
>>> iterator = sequence.__iter__()
>>> iterator.next()
1
>>> iterator.next()
2
>>> for number in iterator:
    print number 
3
4
5

itertoolsに戻ります。パッケージには、さまざまな反復目的の関数が含まれています。特別な順序付けを行う必要がある場合は、これが最初に検討する場所です。

下部には、既存のitertoolsをビルディングブロックとして使用して拡張ツールセットを作成するためのレシピを含む Recipes セクションがあります

そして、必要なことを正確に行う興味深い関数があります。

def consume(iterator, n):
    '''Advance the iterator n-steps ahead. If n is none, consume entirely.'''
    collections.deque(itertools.islice(iterator, n), maxlen=0)

これがどのように機能するかについての簡単で読みやすい例です(Python 2.5)

>>> import itertools, collections
>>> def consume(iterator, n):
    collections.deque(itertools.islice(iterator, n))
>>> iterator = range(1, 16).__iter__()
>>> for number in iterator:
    if (number == 5):
        # Disregard 6, 7, 8, 9 (5 doesn't get printed just as well)
        consume(iterator, 4)
    else:
        print number

1
2
3
4
10
11
12
13
14
15
44

itertools.islice

lines = iter(cdata.splitlines())
for line in lines:
    if exp.match(line):
       #increment the position of the iterator by 5
       for _ in itertools.islice(lines, 4):
           pass
       continue # skip 1+4 lines
    print line

たとえば、expcdataが次の場合:

exp = re.compile(r"skip5")
cdata = """
before skip
skip5
1 never see it
2 ditto
3 ..
4 ..
5 after skip
6 
"""

出力は次のとおりです。

 
スキップ前
 5スキップ後
 6 

Cの例のPython実装

i = 0
while i < 100:
    if i == 50:
       i += 10
    print i
    i += 1

@ [Glenn Maynard]が コメント で指摘したように、i + = 100000000などの非常に大きなジャンプを行う必要がある場合は、単にステップをスキップするのではなく、明示的なwhileループを使用する必要がありますforループ内。

whileの代わりに明示的なisliceループを使用する例は次のとおりです。

lines = cdata.splitlines()
i = 0
while i < len(lines):
    if exp.match(lines[i]):
       #increment the position of the iterator by 5
       i += 5
    else:
       print lines[i]
       i += 1

この例では、上記のisliceの例と同じ出力が生成されます。

16
jfs

あなたが数字でそれをやっているなら、リストの理解はうまくいくことができます:

for i in [x for x in range(0, 99) if x < 50 and x > 59]:
    print i

ただし、イテレータを前方に移動するのは少し難しくなります。おそらくcdataを分割し、一致する行のインデックスを作成し、その行と次の行を削除することによって、カウンターアプローチを行いたくない場合は、事前にリストを設定することをお勧めします。それとは別に、あなたは正直に言うとあなたが作るほど不快ではないカウンターアプローチに固執しています。

別のオプションはこれです:

iterator = iter(cdata.split('\n'))
for line in iterator:
    if exp.match(line):
        for i in range(0, 5):
            try:
                iterator.next()
            except StopIteration:
                break
    else:
        print line
2
Benno

私があなたの思考プロセスに従うかどうかは正確に定かではありませんが、ここで何かを養います。

for i in range(len(cdata.split('\n'))):
  if i in range(50,60): continue
  line = cdata[i]
  if exp.match(line):
    #increment the position of the iterator by 5?
    pass
  print line

あなたが本当に何を求めているのかはわかりませんが、range(len(..))が役立ちます。

1
rh0dium

イテレータから値をドロップできます

_def dropvalues(iterator, vals):
    for i in xrange(vals): iterator.next()
_

ここで、lines = iter(cdata.split('\n'))を操作するイテレータオブジェクトがあることを確認してください。ループします。

1
u0b34a0f6ae

たとえば、イテレータではなくリスト(インデックス可能なシーケンス)を使用しているため、次のことをお勧めします。

lines = cdata.split("\n")
for line in lines[:50]+lines[60:]:
  print line

3つの新しいリストを作成する可能性があるため、これは最も効率的ではありません(ただし、スキップされた部分が処理済みの部分よりも大きい場合、他のオプションよりも効率的かもしれません)が、かなりクリーンで明示的です。

Itertoolsモジュールを使用する気がない場合は、リストをシーケンスに簡単に変換できます。

from itertools import chain, islice
for line in chain(islice(lines, None, 50), islice(lines, 60,None)):
  print line
0
fortran

多分genexpsで。きれいじゃないけど...

そんな感じ:

>>> gx = (line for line in '1 2 x 3 4 5 6 7 x 9 10 11 12 x 1'.split('\n'))
>>> for line in gx:
...   if line == 'x':
...      for i in range(2):
...          line = gx.next()
...   print line

唯一の問題は、gxをnext()-edできるようにすることです。上記の例は、最後のxのために意図的に例外を生成します。

0
mjv