Laxmikant
Laxmikant

Reputation: 2226

Iterator to iterate over a generator

I am parsing an XML file, one of xml tag has a structure like this:

<product>
     <item seq="division-sec">Division</item>
     <item seq="dept-sec">Dept Info</item>
     <item seq="label01">Label 01</item>
     <item seq="label02">Label 02</item>
     ...
     <item seq="labelN">Label N</item>
     <item seq="date-mfg">27-11-2017</item>
     <item seq="date-exp">28-11-2019</item>
</product>  

I have written a generator function to access product labels in a sequence:

def product_labels(xmlpage):
    #... parsed xml here
    for item in xmlpage:
       #-- process item for validation such as case sensitivity, etc
       yield item # ("division-sec", "Division")

Now I'm looking for a function or may be an iterator class, which would allow me to get first, last, prev, next and search methods on it:

class ProdcutReader(object):
     def __init__(self, product_labels):
       self.product_labels = product_labels

     def __iter__(self):
        return self

     def __prev__(self):
        return prev(self.product_labels ) #-- Dont know how to do this :(

     def __next__(self):
        current = self.current(next(self.product_labels))
        return current

     def current(self, obj=None):
         if not obj:
            return self.first()
         return obj

     def first(self):
         return list(self.product_labels)[0]   

    # search by label seq 
    def search(self, seq):
       # Not sure if this is the correct way
       for i in self.product_labels:
           if i[0] == seq:
              self.current(i)
              return i
    ... # With some more methods (if search works I can have some more methods)

So assume I need to use that object, it should work like this:

from product_reader import ProdcutReader as Reader
>>>r = Reader(product_labels)
>>>r.first()
("division-sec", "Division")
>>>r.last()
("date-exp", "28-11-2019")
>>>r.current()  # Let us say current is ("label01", "Label 01")
("label01", "Label 01")
>>>r.next() # or next(r)
("label02", "Label 02")
>>>r.prev()
("dept-sec", "Dept Info")
>>r.search("date-mfg") # This should also set the searched as r.current()  
("date-mfg", "27-11-2017")

If I can get how to write for prev, next and search I will be able to write remaining methods like, first, last, current etc.

Upvotes: 1

Views: 128

Answers (1)

L3viathan
L3viathan

Reputation: 27331

You apparently need random access to any element at any time. To my eyes, I don't see why you don't simply use a list.

If you need the current/next/previous functionality without having to keep track of a counter variable, you could still base your construct on a list:

class ProductReader(object):
    def __init__(self, product_labels):
        self.generator = product_labels
        self.active_generator = self.generator()
        self.element = None
        self.cur = -1

    def at_n(self, index):
        if self.cur > index:
            self.active_generator = self.generator()
        while len(self.storage) < index+1:
            self.element = next(self.active_generator)
        self.cur = index
        return self.element

    def current(self):
        if self.cur > -1:
            return self.element

    def last(self):
        try:
            while True:
                self.element = next(self.generator)
                self.cur += 1
        except StopIteration:
            return self.element

    def first(self):
        return self.at_n(0)

    def next(self):
        return self.at_n(self.cur+1)

    __next__ = next

    def prev(self):
        return self.at_n(self.cur-1)

    def search(self, query):
        oldcur = self.cur
        self.active_generator = self.generator()
        for i, element in enumerate(self.generator()):
            if query in element:
                self.cur = i
                self.element = element
                return element
        self.at_n(self.cur)  # reset to old state
        return None

Upvotes: 1

Related Questions