2

ユーザー入力を取得するために、単純な方法でリストの内容をループしてきました。

for n in [ 1, 2, 3, 4 ]:
 command = raw_input ( "%d >> " % (n) )
 ...

元に戻す機能を実装したいと考えています。これは、反復を前の値に「巻き戻す」ことを意味します。n の値を減らす単純な方法を次に示しますが、リストへの内部ポインターが変更されていないため、元の値をスキップします。

for n in [ 1, 2, 3, 4 ]:
 if f(n):
  n -= 1
 ...

ドキュメントには iterator.next() がありますが、iterator.last() はありません。整数インデックスでリスト メンバーにアクセスするように切り替え、自分でインデックスを操作してループを手動でロールすることができると思いますが、これはそれほど脅威ではありませんが、より良い方法はありますか?

4

3 に答える 3

9

ストック Python でこれを行う明確な方法はありませんが、バックトラッキングをサポートする独自の反復子を作成するのは簡単です。たとえば、「シーク可能な」反復子が続きます。同じ要素を繰り返すには相対 0 をシークし、前の要素に戻るには相対 -1 をシークします。

注: このスタイルの反復は「保証された前方進行」を享受しないため、間違いなく、無限ループが発生しやすくなります。

class SeekableIterator(object):
    """An iterator that supports seeking backwards or forwards."""

    def __init__(self, iterable):
        """Make a SeekableIterator over an iterable collection."""

        self.iterable = iterable
        self.index = None

    def __iter__(self):
        """Start the iteration."""

        self.index = 0
        return self

    def next(self):
        """Return the next item in the iterator."""

        try:
            value = self.iterable[self.index]
            self.index += 1
            return value
        except IndexError:
            raise StopIteration

    def seek(self, n, relative=False):
        """Adjust the loop counter, either relatively or to an absolute index.
        Note that seeking 0 replays the current item. Seeking -1 goes to
        the previous item. If the adjustment pushes the index outside the
        iterable's bounds, raise an index error."""

        if relative:
            self.index += n - 1
            # NB index already advanced one in next(), so subtracting one here
        else:
            self.index = n
        if self.index < 0 or self.index >= len(self.iterable):
            raise IndexError


if __name__ == '__main__':

    import random

    def prob(percent):
        """Return True with roughly the given probability, else False"""
        return random.random() <= (percent * 1.0 / 100.0)

    seeker = SeekableIterator([1, 2, 3, 4])
    for n in seeker:
        print "n:", n

        if prob(50):
            if prob(50):
                print "\tREDO - seeking 0"
                seeker.seek(0, relative=True)
            elif n > 1:
                print "\tUNDO - seeking -1"
                seeker.seek(-1, relative=True)

出力例を次に示します。

n: 1
n: 2
n: 3
n: 4
    REDO - seeking 0
n: 4
    REDO - seeking 0
n: 4
    UNDO - seeking -1
n: 3
n: 4
于 2012-06-19T20:17:30.887 に答える
4

Whileループを使用します。

lis = [1, 2, 3, 4]
i = 0
while i < len(lis):
    if some_condition:
        print(lis[i])
        i += 1
    elif some_other_condition:
        print(lis[i])
        i -= 1
于 2012-06-19T19:44:08.347 に答える
1

コンセンサスは、いいえ、python イテレータをバックトラックさせる方法がないということです。このスレッドには詳細があります:

Pythonイテレータを逆行させますか?

ただし、ループを再構築して、わずかに異なる形式にすることができる場合もあります。次の pythonlike 疑似コードを検討してください。

unprocessed = [1,2,3,...]
processed = []

traverse(unprocessed, processed, processor_function):
    item = unprocessed.head()
    unprocessed = unprocessed.tail()
    processed.prepend(item)
    if processor_function != None:
        processor_function(item)

プライマリ ループ ロジックは、必要に応じてトラバースをいずれかの順序で呼び出し、逆方向の反復をエミュレートするために処理済みと未処理を切り替えることができます。None単に処理をスキップするために渡すことを含め、任意の処理関数を渡すことができます。すべての要素の処理が完了すると、リストは次のようになります。

unprocessed = []
processed = [...,3,2,1]

それは一種のチューリングマシン風です。「読み取りヘッド」は常に最初のリストの最初の要素の上にあり、読み取りヘッドの「右側」にあるすべての要素は、距離に応じて昇順のインデックスを持つ最初のリストにあり、読み取りの「左側」にあるすべての要素は聞こえますは 2 番目のリストにあり、インデックスは距離に応じて昇順になります。読み取りヘッドに「最も近い」要素は、各リストの先頭に近い要素です。

于 2012-06-19T19:45:22.340 に答える