Soru Bir python yineleyici yapmak geriye mi gidiyor?


Bir geriye doğru gitmek için bir python listesi yineleyici yapmak için var mı?

Temelde buna sahibim

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()

Bu kodu çalıştırmak çıktıda sonuçlanır:

a
1
2
3
Crap i skipped C

Bana neden çıktı verdiğini biliyorum, ancak bir adımda str () yönteminde geriye doğru adım atabileceğim bir yol var mı?

DÜZENLE

Tamam belki bunu daha açık hale getirmek için. Tam tersini yapmak istemiyorum, temelde eşdeğerini yapmak için kolay bir yol olup olmadığını bilmek istiyorum iki yönlü python içinde yineleyici?


22
2018-05-05 22:23


Menşei


Sadece kullanarak ne yanlış reversed? Belli bir şekilde geriye doğru gidebilmek mi istiyorsunuz yoksa sadece sonuçları geriye mi almak istiyorsunuz? - jathanism
Oh .... orta iterasyonu durdurup yedeklemek ister misin? Büyük olasılıkla, listenin geçtiğiniz bölümünü değiştirip onu kullanarak çaprazlamak zorunda kalacaksınız. reversed() - D.Shawley
Bunu yapabilirim, ancak bu icky koduyla sonuçlanır, C ++ 'da iki yönlü iterasyon desteği vardır. - UberJumper
@uberjumper: tembel olarak değerlendirilen sekanslar için jeneratörler tarafından kullanılan yineleyici protokolü kavramı, genel iki yönlü yineleyicileri Python'da çok daha zor hale getirir. En iyi seçeneğiniz, koleksiyonun dizinini takip eden ve Tamás'ın uygulandığı şekilde yedeklenen özel bir yineleyici ile dizininin üzerinden indekslenmesidir. - D.Shawley


Cevaplar:


Hayır, genelde bir Python yineleyicisi geriye doğru gidemezsiniz. Ancak, sadece bir kez geri adım atmak isterseniz, şu şekilde deneyebilirsiniz:

def str(self, item):
    print item

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

Daha sonra, önceki öğeye istediğiniz zaman erişebilirsiniz. prev.

İki yönlü bir yineleyiciye gerçekten ihtiyacınız varsa, kendiniz bir tane uygulayabilirsiniz, ancak yukarıdaki çözümden daha fazla yük getirecektir:

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

22
2018-05-05 22:30



Evet, bunu engellemeye çalışıyorum, çünkü bu biraz rahatsız edici bir yük ekleyecektir: / - UberJumper
Eklendi bidirectional_iterator Yukarıdaki örnekte, sorunuzu güncellediğinizi anladım, ancak bu, ilk çözümümden daha fazla yük getirecektir. - Tamás
Bu sınıfa dikkat edin değil uygun bir yineleyici üretin. Örneklerinde .next () ve .prev () öğesini elle çağırabilirsiniz, ancak yineleyici for döngü veya liste anlama. Bu bir TypeError: iter() returned non-iterator of type 'bidirectional_iterator'. - etuardu
Garip bir şekilde, benim için çalışıyor (Python 2.7.1, Mac OS X). Python'da bir yineleyici ihtiyacı olan AFAIK bir next() yöntem ve bir __iter___ kendini geri döndürüyor. - Tamás
@etuardu: Python 3 kullanıyor musunuz? iirc next yeniden adlandırıldı __next__. - Benjamin Hodgson♦


Bir şeyi özlüyorum ya da Python öğreticisindeki Iterator bölümünde açıklanan teknik?

>>> 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

Bunun iteratörün geriye doğru yürümediğini biliyorum, ama eminim ki bunu genel olarak yapmanın bir yolu yoktur. Bunun yerine, ayrık bir koleksiyonu ters sırayla yürüten bir yineleyici yazın.

Düzenle ayrıca kullanabilirsiniz reversed() Kendi koleksiyonunuzu yazmak zorunda kalmamak için herhangi bir koleksiyon için tersine döndürülen bir iteratör elde etmek için

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

5
2018-05-05 23:00



Bunun için daha basit ve eşdeğer bir çözüm kullanmak reversed tersine çevrilmiş bir bağlantı üzerinden yürür bir yineleyici döndüren yerleşik. - Tamás
@ Tamás: Düzenlemeyi söylediğin gibi yazıyordum. İlk yanıtı yayınlayana kadar düşünmedim. - D.Shawley
Tüm yineleyiciyi ters çevirmek istemiyorum, python içinde iki yönlü bir yineleyicinin eşdeğerini arıyorum. - UberJumper
Tam olarak hangi sorunun çözüldüğünü bilmek isterim sadece iki yönlü bir yineleyici kavramı ile, ve olamaz tarafından çözülmek reversed() - rossipedia
@BryanRoss: Tahminimce algoritma tarafından yedeklenecek n belirli bir değerle karşılaştığında yerler. Bu, siz onu geçerken diziyi kaydederek ve çözerek kullanılabilir reversed() Birkaç adımı yedeklemek için ezbere dizisi üzerinde. - D.Shawley


Yineleyici, tanım gereği bir nesnedir. next() yöntem - hiçbir söz prev() olursa olsun. Bu nedenle, sonuçlarınızı önbelleğe almanız gerekir. Böylece, tekrar ziyaret edebilir veya yineleyicinizi yeniden etkinleştirebilirsiniz, böylece sonuçlarınızın olmasını istediğiniz sırayla döndürür.


3
2018-05-05 22:49





Sorunuza bağlı olarak, böyle bir şey istediğiniz gibi geliyor:

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
2018-05-05 23:18





Yineleyicinizi, geriye gitmesini sağlamak için yineleyici yardımcısına sarabilirsiniz. Yinelenen değerleri bir koleksiyonda saklar ve geriye doğru giderken bunları yeniden kullanır.

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]

Kullanım buna benzer:

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
2018-05-08 21:56





Ben senin problemini çözmene yardım edeceğini düşünüyorum

    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
2018-02-01 04:35