Neater way of making indexes?

Steven Taschuk staschuk at telusplanet.net
Sat May 31 00:23:14 EDT 2003


Quoth Jane Austine:
> 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?

    def indices(*limits):
        ind = [0]*len(limits)
        while True:
            yield tuple(ind)
            for i in range(len(limits)-1, -1, -1):
                ind[i] += 1
                if ind[i] < limits[i]:
                    break
                ind[i] = 0
            else:
                break

This method is just counting with varying bases, carries as
appropriate, stopping when the carry goes past the most
significant digit.

There's a recipe for a slightly more general problem in the Python
Cookbook:

    <http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/159975>

I can't recommend the original version, but Raymond Hettinger's
suggested simplification is quite easy on the eyes.

-- 
Steven Taschuk             "The world will end if you get this wrong."
staschuk at telusplanet.net     -- "Typesetting Mathematics -- User's Guide",
                                 Brian Kernighan and Lorrinda Cherry





More information about the Python-list mailing list