2010-05-05 39 views
17

Có cách nào để tạo một trình lặp danh sách python để quay ngược lại không?Tạo một trình lặp python đi ngược?

Về cơ bản tôi có điều này

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

Chạy mã này kết quả trong đầu ra:

a 
1 
2 
3 
Crap i skipped C 

tôi biết tại sao nó mang lại cho tôi kết quả, tuy nhiên có một cách tôi có thể bước lùi trong str() phương pháp, bởi một bước?

EDIT

Được rồi có lẽ để làm điều này rõ ràng hơn. Tôi không muốn làm một đảo ngược hoàn toàn, về cơ bản những gì tôi muốn biết nếu có một cách dễ dàng để làm tương đương với một hai chiều iterator trong python?

+0

Có gì sai khi chỉ sử dụng 'đảo ngược'? Bạn rõ ràng muốn có thể quay trở lại, hoặc chỉ muốn kết quả ngược? – jathanism

+1

Ồ .... bạn có muốn dừng giữa lặp lại và sao lưu không? Có thể bạn sẽ phải cache một phần của danh sách mà bạn đã duyệt qua và đi qua nó bằng cách sử dụng 'reversed()' –

+0

Tôi có thể làm điều đó, tuy nhiên kết thúc dẫn đến mã icky, trong C++ chúng ta có hỗ trợ lặp hai chiều. – UberJumper

Trả lời

17

Không, nói chung bạn không thể tạo một trình lặp Python trở về sau. Tuy nhiên, nếu bạn chỉ muốn lùi lại một lần, bạn có thể thử một cái gì đó như thế này:

def str(self, item): 
    print item 

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

Sau đó bạn có thể truy cập vào các yếu tố trước bất cứ lúc nào trong prev.

Nếu bạn thực sự cần một iterator hai chiều, bạn có thể thực hiện một mình, nhưng nó có khả năng giới thiệu chi phí thậm chí nhiều hơn các giải pháp trên:

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

Vâng, tôi đang cố gắng tránh điều này tuy nhiên, vì điều này sẽ thêm một chút chi phí gây phiền nhiễu:/ – UberJumper

+0

Đã thêm ví dụ 'bidirectional_iterator' ở trên vì tôi đã thấy rằng bạn đã cập nhật câu hỏi của mình, nhưng điều này có thể sẽ được giới thiệu hơn cả chi phí đầu tiên của tôi. –

+0

Lưu ý rằng lớp này không __not__ tạo ra một trình vòng lặp thích hợp. Bạn có thể gọi thủ công .next() và .prev() trên các cá thể của nó, nhưng bạn không thể sử dụng các cơ sở của trình vòng lặp lợi nhuận như truyền nó trong một vòng lặp 'for' hoặc một danh sách hiểu. Điều đó sẽ nâng cao một 'TypeError: iter() trả về non-iterator của kiểu 'bidirectional_iterator''. – etuardu

3

Một iterator là theo định nghĩa một đối tượng với phương pháp next() - - không đề cập đến số prev(). Vì vậy, bạn phải nhớ kết quả của bạn để bạn có thể xem lại chúng hoặc thực hiện lại trình lặp của bạn để nó trả về kết quả theo thứ tự bạn muốn.

3

Tôi có thiếu một cái gì đó hay không có thể giúp bạn sử dụng technique described in the Iterator section in the Python tutorial?

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

Tôi biết rằng điều này không đi bộ iterator ngược, nhưng tôi khá chắc chắn rằng không có cách nào để làm điều đó trong chung. Thay vào đó, hãy viết một trình lặp đi lặp lại một bộ sưu tập rời rạc theo thứ tự ngược lại.

Sửa bạn cũng có thể sử dụng chức năng reversed() để có được một iterator đảo ngược đối với bất kỳ bộ sưu tập để bạn không cần phải viết riêng của bạn:

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

Một giải pháp đơn giản và tương đương cho giải pháp này là sử dụng 'được đảo ngược' tích hợp trả về một trình lặp đi qua kết nối theo thứ tự đảo ngược. –

+0

@ Tamás: Tôi đã viết bản chỉnh sửa giống như bạn đã đề cập. Tôi đã không nghĩ về nó cho đến sau khi tôi đăng câu trả lời đầu tiên. –

+2

Tôi không muốn đảo ngược toàn bộ trình vòng lặp mà tôi đang tìm kiếm tương đương với trình lặp vòng hai chiều trong python. – UberJumper

1

Dựa trên câu hỏi của bạn, có vẻ như bạn muốn một cái gì đó như thế này:

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 
0

tôi nghĩ rằng thi sẽ giúp bạn giải quyết vấn đề của bạn

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)) 
Các vấn đề liên quan