开发者

how code a function similar to itertools.product in python 2.5

I have a list of tuples, e.g:

A=[(1,2,3), (3,5,7,9), (7)] 

and want to generate al开发者_如何学Cl permutations with one item from each tuple.

1,3,7
1,5,7
1,7,7
...
3,9,7

I can have any number of tuples and a tuple can have any number of elements. And I can't use itertools.product() because python 2.5.


docs of itertools.product have an example of how to implement it in py2.5:

def product(*args, **kwds):
    # product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy
    # product(range(2), repeat=3) --> 000 001 010 011 100 101 110 111
    pools = map(tuple, args) * kwds.get('repeat', 1)
    result = [[]]
    for pool in pools:
        result = [x+[y] for x in result for y in pool]
    for prod in result:
        yield tuple(prod)


def product(*iterables):
    """ Equivalent of itertools.product for versions < 2.6,
        which does NOT build intermediate results.
        Omitted 'repeat' option.
        product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy
    """
    nIters = len(iterables)
    lstLenths = []
    lstRemaining = [1]
    for i in xrange(nIters-1,-1,-1):
        m = len(iterables[i])
        lstLenths.insert(0, m)
        lstRemaining.insert(0, m * lstRemaining[0])
    nProducts = lstRemaining.pop(0)

    for p in xrange(nProducts):
        lstVals = []

        for i in xrange(nIters):
            j = p/lstRemaining[i]%lstLenths[i]
            lstVals.append(iterables[i][j])
        yield tuple(lstVals)


When playing around with generators, I too found a version of itertools.product, and it is almost as fast as the (native) library version, while being 100% compatible with it, and it does not build intermediate results:

def product(*args, **kwds):
    "Alternative fast implementation of product for python < 2.6"
    def cycle(values, uplevel):
        for prefix in uplevel:       # cycle through all upper levels
            for current in values:   # restart iteration of current level
                yield prefix + (current,)

    stack = (),             
    for level in tuple(map(tuple, args)) * kwds.get('repeat', 1):
        stack = cycle(level, stack)  # build stack of iterators
    return stack

With python 2.7.3, I found the performance to be really good (usually only about a factor of 5-10 slower with essentially the same memory usage).

>>> import itertools as itt
>>> timeit for _ in itt.product(range(20), range(3), range(150)): pass
1000 loops, best of 3: 221 µs per loop
>>> timeit for _ in product(range(20), range(3), range(150)): pass
1000 loops, best of 3: 1.14 ms per loop

EDIT: made code even simpler and Python 3-ready.


The itertools documentation contains full code showing what each function is equivalent to. The product implementation is here.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜