Python for 循环偏移 (Itertools.product)

Posted

技术标签:

【中文标题】Python for 循环偏移 (Itertools.product)【英文标题】:Python for loop offset (Itertools.product) 【发布时间】:2014-02-12 17:13:51 【问题描述】:

以下代码使用01 生成所有可能的组合,其中必须使用四位数字。

import itertools
for i in itertools.product([0, 1], repeat=4):
    print i

输出:

(0, 0, 0, 0)(0, 0, 0, 1)(0, 0, 1, 0)(0, 0, 1, 1)(0, 1, 0, 0)(0, 1, 0, 1)(0, 1, 1, 0)(0, 1, 1, 1)(1, 0, 0, 0)(1, 0, 0, 1)(1, 0, 1, 0)(1, 0, 1, 1)(1,1, 0, 0)(1, 1, 0, 1)(1, 1, 1, 0)(1, 1, 1, 1)

我希望能够为 for 循环设置偏移量。示例:

import itertools
offSet = 10
for i in itertools.product([0, 1], repeat=4):
    # Some code that applies the offset
    print i

然后会输出:

(1, 0, 1, 0)(1, 0, 1, 1)(1,1, 0, 0)(1, 1, 0, 1)(1, 1, 1, 0)(1, 1, 1, 1)

如何在这个 for 循环中应用这样的偏移量?

注意:所使用的代码已简化。因为我实际上为repeat 使用了一个非常大的值,所以性能很重要。我无法承受要计算的偏移量之前的可能组合。

【问题讨论】:

无论如何您可以“计算”起点(这将特定于您的特定用例) - 否则,唯一的方法就是生成值并丢弃,直到您感兴趣在他们... 这只是笛卡尔积;如果您不需要生成其中的一部分,请将您的问题分解为子集;您可以在此处使用链接产品生成子部分。 看起来您正试图在整数的两个二进制表示之间切换。也许只是循环 xrange(start,end) 并将整数插入您需要的二进制格式? 【参考方案1】:

这个怎么样:

In [29]: offSet = 10

In [30]: repeat = 4

In [31]: for i in xrange(offSet, 2**repeat):
    print tuple(int(x) for x in bin(i)[2:])
   ....:     
(1, 0, 1, 0)
(1, 0, 1, 1)
(1, 1, 0, 0)
(1, 1, 0, 1)
(1, 1, 1, 0)
(1, 1, 1, 1)

【讨论】:

【参考方案2】:

这里有一个定义,它接受一个二进制文件(在 Python 中,用 '0b1010101' 中的字符串表示)(或者一个省略了 0b 部分的易于人类可读和可写的版本)并以以下形式返回范围字符串元组的迭代器(延迟创建)。您可以使用 list() 实现范围。

def binrange(start, stop=None):
    '''
    given bin strings return iterator of zeros and ones
    e.g. 
    >>> list(binrange(bin(8))) # bin(8) returns '0b1000'
    [(0, 0, 0, 0), (0, 0, 0, 1), (0, 0, 1, 0), (0, 0, 1, 1), (0, 1, 0, 0), (0, 1, 0, 1), (0, 1, 1, 0), (0, 1, 1, 1)]
    >>> list(binrange('10', bin(4))) # bin(4) returns '0b100'
    [(0, 1, 0), (0, 1, 1)]
    '''
    if stop is None:
        start, stop = '0', start
    start = start[2:] if start.startswith('0b') else start
    stop = stop[2:] if stop.startswith('0b') else stop
    length = len(stop)
    for i in xrange(long(start, 2), long(stop, 2)): # in Python3, use range(), not xrange()
        yield tuple(int(j) for j in ('0:b'.format(i).zfill(length)))
        # above line replaces the following commented line
        # yield tuple(int(j) for j in ('0:fillalignwidthb'.format(i, fill=0, align='>', width=length)))

print(list(binrange(bin(1000**3), bin(1000**3+3))))
print(list(binrange('1000')))
print(list(binrange('0b100')))

打印出来:

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

【讨论】:

【参考方案3】:

你可以使用islice:

from itertools import product, islice

i = islice(product([0, 1], repeat=4), 10, None) 
print list(i)

这仍然失败:

在要计算的偏移量之前,我无法承受可能的组合。

这并不是迭代器的真正用途。无论如何,您实际上只是在尝试以二进制计数,此处的其他答案将起作用

【讨论】:

islice 仍然计算直到起始值的值,它只是不会返回它们。

以上是关于Python for 循环偏移 (Itertools.product)的主要内容,如果未能解决你的问题,请参考以下文章

如何在限制 LIMIT 的情况下循环 python API 并可以提供偏移量

任何加速 itertool.product 的方法

如何限制for循环中的网络调用次数?

pd.DataFrame 上的 for 循环继续运行,但在 100 次迭代后停止工作

如果我使用itertool中的islice从第5行开始,如何使用DictReader?

python中for循环的用法