[Python-Dev] synchronized enumerate

Chris or Leslie Smith smiles at worksmail.net
Mon Dec 19 06:42:39 CET 2005


I see that there is a thread of a similar topic that was posted recently ( enumerate with a start index  ) but thought I would start a new thread since what I am suggesting is a little different.

Whenever I use enumerate, I am doing so because I will use the index to access some other element in the list (the previous or next, usually) while also looking at the element that is returned from enumerate.  Several times, however, in the development phase of the work, I end up sending a subset of the list at hand and then get bitten by the fact that the indices returned by enumerate are not the indices of the original list, they are the indices of the slice that I sent. e.g. in the following, "0" is the first index but I wanted it to be 3

###
>>> start=3
>>> count=5
>>> for i, x in enumerate(range(10)[start:start+count]):
...  print i, x
...  
0 3
1 4
2 5
3 6
4 7
>>> 
###

What I would propose is an optional slice argument to the enumerate routine that would allow enumerate to return elements that are synchronized with the original list list/iterable elements. e.g.

def enum(l, slc=None):
    if slc==None:
        for i, dat in enumerate(l):
            yield i, dat
    else:
        if type(slc)<>slice:
            raise TypeError, "slc must be a valid slice"
        start, step = slc.start, slc.step
        # we need actual values for start and step, so check for None
        # and supply defaults
        if step==None:step=1
        if start==None:
            if step>0:
                start=0
            else:
                start=-1
        for i, dat in enumerate(l[slc]):
            j = i*step+start
            if j<0: j+=len(l)
            yield j, dat
###
>>> for i, x in enum(range(10), slice(start, start+count)):
...  print i, x
...  
3 3
4 4
5 5
6 6
7 7
>>> for i, j in enum(range(10), slice(None,None,-3)):
...  print i,j
...  
9 9
6 6
3 3
0 0
>>> 
###

An advantage to processing the iteratable with a slice argument is that then the slice information is given only once and it can do 2 things: slice the original iterable and provide the synchronized indices.

NOTE: the same thing that I am proposing could also be done with count and izip if count had a step argument, but it's more ackward and you have to supply the same information in two places:

>>> def count(start, step=1):
...  for i in itertools.count(start):
...   yield start+(i-start)*step
... 
>>> 
>>> start=3; stop=None; step=2
>>> for i,j in itertools.izip(count(start, step), itertools.islice(range(10), start, stop, step)):
...  print i,j
...  
3 3
5 5
7 7
9 9

A "P.S." question for this email is, was there a reason to leave step out of itertools.count? 

/c


More information about the Python-Dev mailing list