Neater way of making indexes?

Brandon Beck bbeck at NOSPAM.austin.rr.com
Fri May 30 23:51:54 EDT 2003


Have a look at this, it's slightly different from your example in the
way it is called, and it's a generator since these lists can get quite
large.  It's also longer, but should be more readable, and hopefully
more understandable.  Your method may be faster since you seem to use
more builtin looping functions.  I didn't attempt to profile them.


from __future__ import generators
import operator

# Think of indices as a len(indices) digit number where each digit is of
a different base.
# The base of the number in position i is limits[i].  The next method
basically increments
# indices by one and takes into account carrying, just like you learned
in 1st grade.  The
# rightmost digit is incremented by one, and if it exceeds its base,
then it is reset to zero,
# and a 1 is "carried" to the digit to the left.  This repeats until a
digit can be incremented
# without exceeding its base.
def next(indices, limits):
        done = False
        index = len(indices)-1

        while not done and index >= 0:
                indices[index] += 1

                if indices[index] >= limits[index]:
                        indices[index] = 0
                        index -= 1
                else:
                        done = True

# This is just a simple wrapper method around the next method in order
to make the
# interface similar to the one you presented.  If you don't want this to
be a generator
# then replace the yield statement with an append to a list collecting
the results.
def indexes(*limits):        # you probably want to call this the proper
plural of index, indices
        indices = [0]*len(limits)
        num = reduce(operator.mul, limits, 1)
        while num > 0:
                yield tuple(indices)
                next(indices, limits)
                num -= 1


>>> indexes(4)
<generator object at 0x008AB1D8>
>>> list(indexes(4))
[(0,), (1,), (2,), (3,)]
>>> list(indexes(3, 2, 4))
[(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 0, 3), (0, 1, 0), ..., (2, 1, 2),
(2, 1, 3)]




"Jane Austine" <janeaustine50 at hotmail.com> wrote in message
news:ba1e306f.0305301709.1bed6424 at posting.google.com...
> The function returns a list of ordered indexes for nested for-loops of
> given input ranges.
>
> >>> from itertools import *
> >>> def indexes(upto):
>     multi=lambda alist:reduce(lambda x,y:x*y,alist,1)
>     g=[ cycle(chain(*[repeat(each,multi(upto[i+1:])) for each in
> range(upto[i])]))
>         for i in range(len(upto))]
>     return list(islice(izip(*g),multi(upto)))
>
> >>> indexes((4,))
> [(0,), (1,), (2,), (3,)]
> >>> indexes((3,2,4))
> [(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 0, 3), (0, 1, 0), (0, 1, 1), (0,
> 1, 2), (0, 1, 3), (1, 0, 0), (1, 0, 1), (1, 0, 2), (1, 0, 3), (1, 1,
> 0), (1, 1, 1), (1, 1, 2), (1, 1, 3), (2, 0, 0), (2, 0, 1), (2, 0, 2),
> (2, 0, 3), (2, 1, 0), (2, 1, 1), (2, 1, 2), (2, 1, 3)]
>
> I don't like this code too much. Any suggestions?
>
> Jane.






More information about the Python-list mailing list