문제

The following code generates all possible combinations using 0 and 1, where four digits have to be used.

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

Output:

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

I would like to be able to set an offset for the for loop. Example:

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

Which would then output:

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

How can I apply a such offset to this for loop?

Note: The code being used is simplified. As I am actually using a very large value for repeat, performance matters. I cannot afford the possible combinations before the offset to be calculated.

도움이 되었습니까?

해결책

How about this:

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)

다른 팁

Here's a definition that takes a binary (in Python, represented by a string as in '0b1010101') (or an easy human readable and writable version that leaves out the 0b part) and returns the range in the form of an iterator of tuples of strings (which is created lazily). You can materialize the range with a 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:{fill}{align}{width}b}'.format(i, fill=0, align='>', width=length)))

and

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

prints out:

[(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)]

You could use islice:

from itertools import product, islice

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

This still fails with respect to:

I cannot afford the possible combinations before the offset to be calculated.

This isn't really what iterators are for. At any rate, you're actually just trying to count in binary, and the other answers here will work

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top