synchronized enumerate

smichr at gmail.com smichr at gmail.com
Mon Dec 19 22:53:56 EST 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.

I posted a very similar item to python-dev, but they said to post it
here. Tutor also said that if anything is to be considered as PEP
worthy, it should be run through here first.  So...here goes.

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

There is a "flexible enumerate()" in the ASPN Cookbook that shows how
to return an arbitrary integer starting point for an iterable,

http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/307582

but I would vote against that since enumerate is suppose to give
indices of the original list.  What I would like to see supported is
the concept that enumerate should give indices and items from an
iterable--it does right now--but it should also allow you to access a
different portion of the original list and *still* give the indices of
that slice.  What I propose is an optional slice argument that would be
used to return the sliced indices and items:

def enum(l, slc=None):
    if slc==None: #the usual ennumerate
        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) #always give positive indices
            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
xrange, islice and izip, but it's more ackward and you have to supply
the same information in two places:

###
aList = range(10)
>>> start=2;stop=2+5
>>> for i,j in itertools.izip(xrange(start, stop), itertools.islice(range(10), start, stop)):
... 	print i,j
...
2 2
3 3
4 4
5 5
6 6
>>>
###

It just seems that a function which was suppose to simplify accessing
indices and elements of an iterable should easily allow you to look at
a slice of the iterable and get the same synchronized inidces.

/c




More information about the Python-list mailing list