【问题标题】:Merging the results of itertools.product?合并 itertools.product 的结果?
【发布时间】:2014-08-30 03:36:07
【问题描述】:

我正在尝试使用itertools.product 从0-9999 创建一个数字列表。我可以通过执行以下操作从 0000-9999 创建一个列表:

numbers = ['0','1','2','3','4','5','6','7','8','9']
itertools.product(numbers,numbers,numbers,numbers)

虽然我想要0001 之类的条目,但我还想要001、01 和1。

包含这些内容的最有效方法是什么?我应该打电话给itertools.product(numbers,numbers,numbers) 和itertools.product(numbers,numbers),然后以某种方式将它们与原件结合起来,还是有更清洁的方法?

如果我应该拨打另外两个电话并合并,有人可以指点我如何做到这一点吗?我尝试使用.append(),但它抛出了这个错误:

'itertools.product' object has no attribute 'append'

感谢您的帮助。

【问题讨论】:

    标签: python itertools


    【解决方案1】:

    您可以使用嵌套的 listcomp 或 genexp(此处为了显示目的而减小了大小):

    >>> numbers = ['0','1','2']
    >>> [''.join(p) for n in range(1,4) for p in product(numbers, repeat=n)]
    ['0', '1', '2', '00', '01', '02', '10', '11', '12', '20', '21', '22', '000', '001', '002', '010', '011', '012', '020', '021', '022', '100', '101', '102', '110', '111', '112', '120', '121', '122', '200', '201', '202', '210', '211', '212', '220', '221', '222']
    

    【讨论】:

      【解决方案2】:
      numbers = ['0','1','2','3','4','5','6','7','8','9']
      list(''.join(subl) for subl in itertools.chain.from_iterable(itertools.product(numbers, repeat=i) for i in range(1,5)))
      

      【讨论】:

        【解决方案3】:

        现有答案的性能改进:

        from itertools import chain, product
        
        list(map(''.join, chain.from_iterable(product(numbers, repeat=i) for i in range(1, 5))))
        # Or on Python 3.5+ with additional unpacking generalizations:
        [*map(''.join, chain.from_iterable(product(numbers, repeat=i) for i in range(1, 5)))]
        

        如果您只是迭代结果,则省略 list()/[*...] 包装。

        CPython 参考解释器的性能显着提高(在这种情况下不是很多,但对于大型产品来说是显着提高)如下(此处的实现细节):

        1. 它将绝大多数工作推到 C 层,避免了字节码解释器循环开销
        2. product 有 an optimization that reuses the result tuple (包括不需要设置其中的大部分值)如果在请求下一个结果时不存在引用。此优化不适用于 listcomps 和 genexprs (循环结构保持对结果 tuple 的引用的时间足够长,以至于在确定是否可以将 tuple 重用于下一个结果时引用存在),但是 @ 987654329@ 避免了这种情况(它只保留对 tuple 的引用足够长的时间来调用映射器函数,在它产生映射器结果之前将其丢弃)。

        即使在这种情况下,加速也是显着的,按百分比计算,用ipython 微基准测试证明(在这种情况下,在 Linux x64 3.6 安装上):

        >>> %timeit -r5 [''.join(p) for n in range(1, 5) for p in product(nums, repeat=n)]
        24.9 μs ± 95.2 ns per loop (mean ± std. dev. of 5 runs, 10000 loops each)
        >>> %timeit -r5 list(map(''.join, chain.from_iterable(product(numbers, repeat=i) for i in range(1, 5))))
        18.2 μs ± 41.2 ns per loop (mean ± std. dev. of 5 runs, 100000 loops each)
        

        如前所述,此处的增益仅以百分比表示(约 27% 运行时间减少); 6.7 μs 在宏伟的计划中是微不足道的。但是,如果要覆盖的range 变得更大和/或numbers 到product 的集合变得更大,那就更重要了;对于numbers = '0123456789' 和range(1, 8),从 2.54 秒减少到 1.67 秒;渐近而言,节省的费用似乎大约节省了三分之一,当总成本以秒为单位衡量时,将成本降低三分之一是有意义的。

        【讨论】:

          猜你喜欢
          • 2019-05-06
          • 2022-11-21
          • 1970-01-01
          • 2015-10-25
          • 2020-08-20
          • 1970-01-01
          • 2018-07-11
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多