【问题标题】:Calculating the nth result for itertools.product()计算 itertools.product() 的第 n 个结果
【发布时间】:2019-05-06 16:22:32
【问题描述】:

我正在尝试计算 itertools.product() 的第 n 个结果

test = list(product('01', repeat=3))
print(test)

desired_output = test[0]
print(desired_output)

所以而不是得到:

[('0', '0', '0'), ('0', '0', '1'), ('0', '1', '0'), ('0', '1', '1'), ('1', '0', '0'), ('1', '0', '1'), ('1', '1', '0'), ('1', '1', '1')]

我想得到:

('0', '0', '0')

但是,正如您可能已经猜到的那样,它不能很好地扩展。这就是为什么我试图只计算第 n 个值。

我通读了 Nth Combination 但我需要 product() 提供的重复功能

提前致谢!

【问题讨论】:

    标签: python python-3.x combinations itertools combinatorics


    【解决方案1】:

    repeat 功能可以很容易地模拟。这是this博客文章中描述的Ruby代码的python版本。

    def product_nth(lists, num):
        res = []
        for a in lists:
            res.insert(0, a[num % len(a)])
            num //= len(a)
    
        return ''.join(res)
    

    调用这个函数

    >>> repeats = 50
    >>> chars = '01'
    >>> product_nth([chars] * repeats, 12345673)
    '00000000000000000000000000101111000110000101001001'
    

    这里有一些时间测试:

    repeat = 50
    idx = 112345673
    
    %timeit i = product_nth(['01'] * repeat, idx)
    %%timeit
    test = product('01', repeat=repeat)
    one = islice(test, idx, idx+1)
    j = ''.join(next(one))
    
    2.01 s ± 22.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
    36.5 µs ± 201 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
    
    print(i == j)
    True
    

    另一个答案具有误导性,因为它歪曲了islice 的功能。例如,请参阅:

    def mygen(r):
        i = 0
        while i < r:
            print("Currently at", i)
            yield i
            i += 1
    
    list(islice(mygen(1000), 10, 11))
    
    # Currently at 0
    # Currently at 1
    # Currently at 2
    # Currently at 3
    # Currently at 4
    # Currently at 5
    # Currently at 6
    # Currently at 7
    # Currently at 8
    # Currently at 9
    # Currently at 10
    # Out[1203]: [10]
    

    islice 将逐步执行每一次迭代,丢弃结果直到指定索引。在对product 的输出进行切片时也会发生同样的情况——该解决方案对于大 N 来说效率很低。

    【讨论】:

      【解决方案2】:

      如果你构建整个列表,当然不会很好地扩展,因为调用 list() 会贯穿整个迭代器。

      如果您只需要第一个值,您可以使用next(test) 来提取迭代器的第一个值。这不需要构建整个列表并且会非常快。

      您也可以使用itertools.islice() 来获取迭代器的特定部分,而无需构建整个列表,而且速度非常快。但要明白,它仍然会迭代到第 N 个值。这是一种非常 Pythonic 的方法,它节省内存且易于阅读。这是否足够快取决于您的 N 需要多大。例如,这对我来说很快就会产生第 200000 个组合的值:

      from itertools import product, islice
      
      test = product('01', repeat=20)
      one = islice(test, 200000, 200001)
      print(''.join(next(one)))
      
      # 00110000110101000000
      

      【讨论】:

      • @JacobW.Dallas 这个答案具有误导性。组合确实不是立即生成的。 islice 生成并丢弃直到指定索引的所有内容。在我的回答中查看一些 timeit 测试。
      • @coldspeed 除了一些夸张之外,这是一个很好且非常 Python 的解决方案,直到组合的数量如此之多以至于它不是。它当然不值得一票否决。
      • 解决方案本身并没有错,只是使用了误导性的语言。 dv 就是为了这个。
      猜你喜欢
      • 2011-03-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-30
      • 2011-04-03
      • 2012-02-08
      • 2012-10-20
      • 2012-03-26
      相关资源
      最近更新 更多