Pythonic迭代整数位的方法

时间:2012-01-17 17:13:06

标签: python binary iterator

让二进制文件为a=1091101101。如何迭代此数字的位,例如:[64, 32, 8, 4, 1]

7 个答案:

答案 0 :(得分:44)

只需从二进制表示中获取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

答案 1 :(得分:10)

我的方法:

def bits(number):
    bit = 1
    while number >= bit:
       if number & bit:
           yield bit
       bit <<= 1

我认为它没有内置功能。

我也想知道对你所做的事情是否有更好的方法。很有可能你真的不想迭代这样的位。他们可能是一个更好的方式。

出于好奇,我对这里发布的方法进行了一些计时,我的结果是:

Winston 2.35238099098
F.J. 6.21106815338
F.J. (2) 5.21456193924
Sven 2.90593099594
Duncan 2.33568000793
freegnu 4.67035484314

F.J。转换成一个字符串,我猜这会伤害他的表现。各种优化尝试都有所帮助,但不足以让Sven产生与其他人相反的情况,如果您确实需要它,这可能是一个优势。 Duncan的方法在速度上获胜(只是勉强)

再次使用340282366920938463463374607431768211457而不是109:

Winston 44.5073108673
F.J. 74.7332041264
Sven 47.6416211128
Duncan 2.58612513542

很好,邓肯!应该指出的是,对于Duncan的方法来说,这几乎是最好的情况,因此它不会总是具有这种戏剧性的优势。

答案 2 :(得分:7)

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

答案 3 :(得分:3)

Python 2.7:

def binary_decomposition(x):
    p = 2 ** (int(x).bit_length() - 1)
    while p:
        if p & x:
            yield p
        p //= 2

示例:

>>> list(binary_decomposition(109))
[64, 32, 8, 4, 1]

答案 4 :(得分:1)

S.O。我不会让这个作为评论,但这里是Duncan's解决方案如何工作的逐行示例。希望这可以澄清正在发生的事情。

我们使用十进制数109作为示例

# 109 is .............. 0110 1101
# ~109 is -110 which is 1001 0010   NOTE: It's -110 instead of -109 because of 1's compliment
# ~109+1 is -109....... 1001 0011
# 109 AND ~109 is...... 0000 0001 = 1  <---- 1st value yielded by the generator
# 109 XOR 1 is......... 0110 1100 = n = 108

# 108.................. 0110 1100
# ~108+1= -108......... 1001 0100
# 108 AND -108......... 0000 0100 = 4  <---- 2nd value yielded by the generator
# 108 XOR 4............ 0110 1000 = n = 104

# 104.................. 0110 1000
# ~104+1............... 1001 1000
# 104 AND -104......... 0000 1000 = 8  <---- 3rd value yielded by the generator
# 104 XOR 8............ 0110 0000 = n = 96

# 96................... 0110 0000
# ~96+1................ 1010 0000
# 96 AND -96........... 0010 0000 = 32 <---- 4th value yielded by the generator
# 96 XOR 32............ 0100 0000 = n = 64

# 64................... 0100 0000
# ~64+1................ 1100 0000
# 64 AND -64........... 0100 0000 = 64 <---- 5th value yielded by the generator
# 64 XOR 64............ 0000 0000 = n = 0; thus, the while loop terminates.

答案 5 :(得分:0)

F.J.答案的效率可以大大提高。

from itertools import count,takewhile
[2**i for i in takewhile(lambda x:109>2**x,count()) if 109&2**i][::-1]

我喜欢一个衬垫:)

我对此和@Duncan进行了快速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

答案 6 :(得分:0)

示例单行解决方案:

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

注意:

  • 在Python 3中使用范围
  • 考虑检查位域是&gt; = 0