Давайте a = 109
или 1101101
в двоичном формате. Как перебирать биты этого числа, например: [64, 32, 8, 4, 1]
Есть хитрость, заключающаяся в том, чтобы просто получить 1 из двоичного представления без необходимости перебирать все промежуточные 0:
def bits(n):
while n:
b = n & (~n+1)
yield b
n ^= b
>>> for b in bits(109):
print(b)
1
4
8
32
64
Эффективность ответа Ф.Дж. может быть значительно улучшена.
from itertools import count,takewhile
[2**i for i in takewhile(lambda x:109>2**x,count()) if 109&2**i][::-1]
Мне нравится один вкладыш:)
Я сделал быстрый timeit.Timer.timeit () против этого и @Duncan. Дункан все еще выигрывает, но не один лайнер, по крайней мере, в том же классе.
from timeit import Timer
duncan="""\
def bits(n):
while n:
b=n&(~n+1)
yield b
n^=b
"""
Duncan=Timer('list(bits(109))[::-1]',duncan)
Duncan.timeit()
4.3226630687713623
freegnu=Timer('[2**i for i in takewhile(lambda x:109>2**x,count()) if 109&2**i][::-1]','from itertools import count,takewhile')
freegnu.timeit()
5.2898638248443604
>>> [2**i for i, v in enumerate(bin(109)[:1:-1]) if int(v)]
[1, 4, 8, 32, 64]
Очевидно, что здесь порядок обратный, вы можете просто использовать это или поменять местами результат:
>>> [2**i for i, v in enumerate(bin(109)[:1:-1]) if int(v)][::-1]
[64, 32, 8, 4, 1]
изменить: Вот немного более длинная версия, которая должна быть более эффективный:
from itertools import takewhile, count
[p for p in takewhile(lambda x: x <= 109, (2**i for i in count())) if p & 109]
Пример однострочного решения:
[1 << bit for bit in xrange(bitfield.bit_length()) if bitfield & (1 << bit)]
Или:
[bit for bit in (1 << n for n in xrange(bitfield.bit_length())) if bitfield & bit]
Примечания: