【问题标题】:Integer to bitfield as a list整数到位域作为列表
【发布时间】:2012-05-06 12:14:56
【问题描述】:

我创建了一种将int 转换为位域(在列表中)的方法,它可以工作,但我确信还有更优雅的解决方案——我已经盯着它看了很长时间。

我很好奇,您如何将int 转换为list 中表示的位域?

def get(self):
    results = []

    results.append(1 if (self.bits &   1) else 0)
    results.append(1 if (self.bits &   2) else 0)
    results.append(1 if (self.bits &   4) else 0)
    results.append(1 if (self.bits &   8) else 0)
    results.append(1 if (self.bits &  16) else 0)
    results.append(1 if (self.bits &  32) else 0)
    results.append(1 if (self.bits &  64) else 0)
    results.append(1 if (self.bits & 128) else 0)

    return results

def set(self, pin, direction):
    pin -= 1
    if pin not in range(0, 8): raise ValueError

    if direction: self.bits |= (2 ** pin)
    else: self.bits &=~(2 ** pin)

【问题讨论】:

    标签: python list bit-fields


    【解决方案1】:

    定长数组

    固定长度的数组:

    >>> '{0:07b}'.format(12)
    '0001100'
    

    你相信字符串也是一个数组吗?不?见:

    >>> [int(x) for x in '{0:07b}'.format(12)]
    [0, 0, 0, 1, 1, 0, 0]
    

    【讨论】:

      【解决方案2】:

      不适用于负值

      >>> import numpy as np
      >>> [int(x) for x in np.binary_repr(123)]
      [1, 1, 1, 1, 0, 1, 1]
      

      【讨论】:

        【解决方案3】:

        这不使用bin

         b = [n >> i & 1 for i in range(7,-1,-1)]
        

        这是处理任何整数的方法:

         b = [n >> i & 1 for i in range(n.bit_length() - 1,-1,-1)]
        

        bit_length

        如果您希望列表的索引 0 对应于 int 的 lsb,请更改范围顺序,即

        b = [n >> i & 1 for i in range(0, n.bit_length()-1)]
        

        另请注意,如果您尝试表示固定长度的二进制值,则使用 n.bit_length() 可能会导致失败。它返回表示 n 的最小位数。

        【讨论】:

        • 这太完美了——我知道我缺少一个列表理解
        • 它可以这样处理任何整数:[n >> i & 1 for i in range(n.bit_length() - 1,-1,-1)]
        • @mennanov:谢谢,已添加(顺便说一句,如果您有有价值的内容要添加,请随时编辑帖子)。
        • 为了性能,你应该使用%2而不是&1,尽管后者看起来更聪明:timeit.timeit("n=193; n%2")返回0.043587817999650724,而timeit.timeit("n=193; n&1")返回0.0545583209986944(我将n 设置为任意值以避免优化)。
        • 最后一个例子应该是range(0, n.bit_length()) 因为范围停止值不包括在内。
        【解决方案4】:

        我正在为我的程序执行此操作,您可以在其中指定模板以从 int 获取值:

        def field(template, value):
            sums = [int(v) if v.__class__==str else len(bin(v))-2 for v in template]
            return [(value>> (sum(sums[:i]) if i else 0) )&(~(~0<<int(t)) if t.__class__==str else t) for i,t in enumerate(template)]
        

        如何使用
        在模板中,指定与您的位大小相关的整数:

        field([0b1,0b111,0b1111], 204) #>>> [0, 6, 12]
        

        或者您可以使用字符串指定所需的每个值的位大小:(noob 友好)

        field(['1','3','4'], 204) #>>> [0, 6, 12]
        

        编辑:反之亦然:(单独的代码)

        field(['1','3','4'], [0, 6, 12]) #>>> 204
        field([0b1,0b111,0b1111], [0,3,9]) #>>> 150
        

        代码:

        def field(template, value):
            res = 0
            for t, v in zip(template, value)[::-1]: res = (res << (t.bit_length() if t.__class__ is int else int(t)) )|v
            return res
        

        EDIT2:更快的代码^

        【讨论】:

          【解决方案5】:

          这个怎么样:

          def bitfield(n):
              return [int(digit) for digit in bin(n)[2:]] # [2:] to chop off the "0b" part 
          

          这给了你

          >>> bitfield(123)
          [1, 1, 1, 1, 0, 1, 1]
          >>> bitfield(255)
          [1, 1, 1, 1, 1, 1, 1, 1]
          >>> bitfield(1234567)
          [1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1]
          

          不过,这只适用于正整数。

          编辑:

          在这里使用int() 转换为int 有点矫枉过正。这要快得多:

          def bitfield(n):
              return [1 if digit=='1' else 0 for digit in bin(n)[2:]]
          

          查看时间安排:

          >>> import timeit
          >>> timeit.timeit("[int(digit) for digit in bin(123)[2:]]")
          7.895014818543946
          >>> timeit.timeit("[123 >> i & 1 for i in range(7,-1,-1)]")
          2.966295244250407
          >>> timeit.timeit("[1 if digit=='1' else 0 for digit in bin(123)[2:]]")
          1.7918431924733795
          

          【讨论】:

          • [123 &gt;&gt; i &amp; 1 for i in range(7,-1,-1)] 是我机器上最快的。
          • @tMC:我在 Python 2.7.3 和 3.2.3 下的两台 PC(Win 7 Ultimate 64bit)上重做了计时,我的解决方案总是至少快 20%( Python 2) 和 45 % (Python 3)。
          • 差异可以忽略不计。我只是觉得在我的 Linux 笔记本电脑上得到不同的结果很有趣。
          【解决方案6】:

          试试

          >>>n=1794
          >>>bitfield=list(bin(n))[2:]
          >>>bitfield
          ['1', '1', '1', '0', '0', '0', '0', '0', '0', '1', '0']
          

          这对负 n 不起作用,如您所见,它会为您提供一个字符串列表

          【讨论】:

          • +1,我好像忘记了一直有list()构造函数。
          • 即使它不返回整数列表。
          • 这不是 tMC 要求的。他需要一个整数列表,你给他一个字符串列表。与 list() 构造函数一样好,它不是这里的正确工具。
          • map(lambda b: int(b), bitfield)
          • @Kroltan map(int, bitfield)
          猜你喜欢
          • 2011-03-04
          • 2012-09-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多