web-dev-qa-db-ja.com

pythonイテレータを後退させますか?

とにかくpythonリストイテレータを逆方向に作成する方法はありますか?

基本的に私はこれを持っています

class IterTest(object):
    def __init__(self, data):
        self.data = data
        self.__iter = None

    def all(self):
        self.__iter = iter(self.data)
        for each in self.__iter:
            mtd = getattr(self, type(each).__name__)
            mtd(each)

    def str(self, item):
        print item

        next = self.__iter.next()
        while isinstance(next, int):
            print next
            next = self.__iter.next()

    def int(self, item):
        print "Crap i skipped C"

if __name__ == '__main__':
    test = IterTest(['a', 1, 2,3,'c', 17])
    test.all()

このコードを実行すると、出力が生成されます。

a
1
2
3
Crap i skipped C

出力が得られる理由はわかっていますが、str()メソッドを1ステップ逆戻りできる方法はありますか?

[〜#〜]編集[〜#〜]

これをもっと明確にしてください。私は完全な逆を行いたくありません、Pythonでbidirectionalイテレータと同等の簡単な方法があるかどうかを基本的に知りたいですか?

25
UberJumper

いいえ、一般的にPythonイテレータを後退させることはできません。ただし、1度だけ後戻りしたい場合は、次のように試すことができます。

def str(self, item):
    print item

    prev, current = None, self.__iter.next()
    while isinstance(current, int):
        print current
        prev, current = current, self.__iter.next()

その後、prevでいつでも前の要素にアクセスできます。

双方向のイテレータが本当に必要な場合は、自分で実装することができますが、上記のソリューションよりもオーバーヘッドが大きくなる可能性があります。

class bidirectional_iterator(object):
    def __init__(self, collection):
        self.collection = collection
        self.index = 0

    def next(self):
        try:
            result = self.collection[self.index]
            self.index += 1
        except IndexError:
            raise StopIteration
        return result

    def prev(self):
        self.index -= 1
        if self.index < 0:
            raise StopIteration
        return self.collection[self.index]

    def __iter__(self):
        return self
24
Tamás

Pythonチュートリアルのイテレータセクションで説明されている テクニックを使用できませんか?

_>>> class reverse_iterator:
...     def __init__(self, collection):
...         self.data = collection
...         self.index = len(self.data)
...     def __iter__(self):
...         return self
...     def next(self):
...         if self.index == 0:
...             raise StopIteration
...         self.index = self.index - 1
...         return self.data[self.index]
...     
>>> for each in reverse_iterator(['a', 1, 2, 3, 'c', 17]):
...     print each
... 
17
c
3
2
1
a
_

これはイテレータを後方に移動しないことは知っていますが、一般的にそれを行う方法はないと確信しています。代わりに、個別のコレクションを逆の順序で歩く反復子を記述します。

Editreversed() 関数を使用して、コレクションの逆反復子を取得し、自分で書く必要があります:

_>>> it = reversed(['a', 1, 2, 3, 'c', 17])
>>> type(it)
<type 'listreverseiterator'>
>>> for each in it:
...  print each
... 
17
c
3
2
1
a
_
7
D.Shawley

イテレータは、定義上、next()メソッドを持つオブジェクトです。prev()についてはまったく触れられていません。したがって、結果をキャッシュして、再度アクセスできるようにするか、イテレータを再実装して、結果を希望どおりの順序で返す必要があります。

3
ktdrv

あなたの質問に基づいて、あなたはこのようなものが欲しいようです:

class buffered:
    def __init__(self,it):
        self.it = iter(it)
        self.buf = []
    def __iter__(self): return self
    def __next__(self):
        if self.buf:
            return self.buf.pop()
        return next(self.it)
    def Push(self,item): self.buf.append(item)

if __name__=="__main__":
    b = buffered([0,1,2,3,4,5,6,7])
    print(next(b)) # 0
    print(next(b)) # 1
    b.Push(42)
    print(next(b)) # 42
    print(next(b)) # 2
2
David X

イテレーターをイテレーターヘルパーでラップして、後退できるようにすることができます。反復された値をコレクションに格納し、逆方向に移動するときにそれらを再利用します。

class MemoryIterator:
    def __init__(self, iterator : Iterator):
        self._iterator : Iterator = iterator
        self._array = []
        self._isComplete = False
        self._pointer = 0

    def __next__(self):
        if self._isComplete or self._pointer < len(self._array):
            if self._isComplete and self._pointer >= len(self._array):
                raise StopIteration

            value = self._array[self._pointer]
            self._pointer = self._pointer + 1
            return value

        try:
            value = next(self._iterator)
            self._pointer = self._pointer + 1
            self._array.append(value)
            return value
        except StopIteration:
            self._isComplete = True

    def prev(self):        
        if self._pointer - 2 < 0:
            raise StopIteration

        self._pointer = self._pointer - 1
        return self._array[self._pointer - 1]

使用方法は次のようになります。

my_iter = iter(my_iterable_source)
memory_iterator = MemoryIterator(my_iter)
try:
    if forward:
        print(next(memory_iterator))
    else:
        print(memory_iterator.prev())
except StopIteration:
    pass
1

次のコードを使用すると、イテレータを後方に移動できます。

class EnableBackwardIterator:
    def __init__(self, iterator):
        self.iterator = iterator
        self.history = [None, ]
        self.i = 0

    def next(self):
        self.i += 1
        if self.i < len(self.history):
            return self.history[self.i]
        else:
            elem = next(self.iterator)
            self.history.append(elem)
            return elem

    def prev(self):
        self.i -= 1
        if self.i == 0:
            raise StopIteration
        else:
            return self.history[self.i]

使用法:

>>> prev = lambda obj: obj.prev()  # A syntactic sugar.
>>> 
>>> a = EnableBackwardIterator(iter([1,2,3,4,5,6]))
>>> 
>>> next(a)
1
>>> next(a)
2
>>> a.next()  # The same as `next(a)`.
3
>>> prev(a)
2
>>> a.prev()  # The same as `prev(a)`.
1
>>> next(a)
2
>>> next(a)
3
>>> next(a)
4
>>> next(a)
5
>>> next(a)
6
>>> prev(a)
5
>>> prev(a)
4
>>> next(a)
5
>>> next(a)
6
>>> next(a)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
0
AnnieFromTaiwan

Pythonでは、リストとインデックスを使用してイテレータをシミュレートできます。

a = [1,2,3]

current = 1

def get_next(a):
  current = a[a.index(current)+1%len(a)]
  return current
def get_last(a):
  current = a[a.index(current)-1]
  return current # a[-1] >>> 3 (negative safe)

リストに重複が含まれている場合は、インデックスを個別に追跡する必要があります。

a =[1,2,3]
index = 0

def get_next(a):
  index = index+1 % len(a)
  current = a[index]
  return current
def get_last(a):
  index = index-1 % len(a)
  current = a[index-1]
  return current # a[-1] >>> 3 (negative safe)
0
Josh Sharkey

あなたの問題を解決するのに役立つと思います

    class TestIterator():
        def __init__(self):`
            self.data = ["MyData", "is", "here","done"]
            self.index = -1
            #self.index=len(self.data)-1
    def __iter__(self):
        return self

    def next(self):
        self.index += 1
        if self.index >= len(self.data):
            raise StopIteration
        return self.data[self.index]

    def __reversed__(self):
        self.index = -1
        if self.index >= len(self.data):
            raise StopIteration
        return self.data[self.index]

r = TestIterator()
itr=iter(r)
print (next(itr))
print (reversed(itr))
0
dilshad
ls = [' a', 5, ' d', 7, 'bc',9, ' c', 17,  '43', 55, 'ab',22, 'ac']
direct = -1
l = ls[::direct]
for el in l:
    print el

直接は-1逆の場合、または1普通。

0
robert tuw