【问题标题】:how code a function similar to itertools.product in python 2.5如何在 python 2.5 中编写类似于 itertools.product 的函数
【发布时间】:2010-12-13 11:14:40
【问题描述】:

我有一个元组列表,例如:

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

并希望从每个元组中生成一个包含一项的所有排列。

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

我可以有任意数量的元组,一个元组可以有任意数量的元素。 而且我不能使用itertools.product(),因为python 2.5。

【问题讨论】:

  • 请注意,您需要重新定义您的 A。当您说 A=[(1,2,3),(3,5,7,9),(7)] 时,最后的 (7) 被评估为整数,而不是元组。因此它是不可迭代的,product(*A) 会抛出一个 TypeError。如果你说A=(1,2,3),(3,5,7,9),(7,)],那么product(*A) 就可以了。
  • 好的,我明白了,但这是一个过于简单的例子。我有 A 作为 3 数元组列表的列表。但我想删除外部列表并获得 A = 3 数元组列表。我怎么做?我认为最好将此作为一个新的初学者 python 问题。

标签: python


【解决方案1】:

itertools.product 的文档有一个如何在 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)

【讨论】:

  • 修复了这个问题,我不小心复制了 py3.1 文档中的示例。
【解决方案2】:
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)

【讨论】:

    【解决方案3】:

    在玩生成器时,我也找到了itertools.product 的版本,它几乎与(原生)库版本一样快,同时与它 100% 兼容,并且不会构建中间结果:

    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 = iter(((),))             
        for level in tuple(map(tuple, args)) * kwds.get('repeat', 1):
            stack = cycle(level, stack)  # build stack of iterators
        return stack
    

    使用 python 2.7.3,我发现性能非常好(通常只慢大约 5-10 倍,内存使用基本相同)。

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

    编辑:使代码更加简单,并且支持 Python 3。

    【讨论】:

    • 使用 try/except 来结束循环并不是很好。您基本上是依靠错误来使循环短路。
    • 我不同意我滥用“错误”条件来退出循环的指控——StopIteration 是在循环构造中检查的有效条件,因为只要循环在内部使用它终止。请注意,异常和StopIteration 在 Python 中的用途比在 C++ 中的用途更广,参见。也是 Python 之禅。
    【解决方案4】:

    itertools 文档包含完整的代码,显示了每个函数的等价物。 product 的实现是 here

    【讨论】:

    • 谢谢,我想问的太快了。
    猜你喜欢
    • 2017-03-15
    • 2012-09-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-09
    • 2016-08-27
    • 1970-01-01
    相关资源
    最近更新 更多