将二进制转换为数字列表 Python

11

我有以下情况:

x = 0b0111

我想把这个值转换为:

y = [0, 1, 1, 1]
当我把 x = 0b1001 转换成 y = [1, 0, 0, 1] 时,但是当我尝试对 x = 0b0111 做同样的转换,然后用 str(bin(y)) 转回去时,我好像失去了前导的 0,得到了 0b111。有什么建议吗?

1
0b0111 == 0b111 那有什么问题呢?如果你需要列表长度固定,那么只需在开头添加适量的 0 即可。 - Joel Cornett
11个回答

10

一旦你得到了那个字符串0b111,将感兴趣的数字分离出来就很容易了。对于字符串中0b之后的每个字符,将其转换为整数。

[int(d) for d in str(bin(x))[2:]]

bin(x) 返回的对象类型为 _<class 'str'>_,我认为我们不需要再显式地将其转换为str(),下面的代码应该可以工作:**[int(d) for d in bin(x)[2:]]**。 - MightyInSpirit

5

就这个问题而言,一个纯算术解决方案似乎稍微快一点:

import timeit

def bits1(n):
    b = []
    while n:
        b = [n & 1] + b
        n >>= 1
    return b or [0]

timeit.timeit(lambda: bits1(12345678))
[out] 7.717339038848877

def bits2(n):
    return [int(x) for x in bin(n)[2:]]


timeit.timeit(lambda: bits2(12345678))
[out] 10.297518014907837

2019年更新:在Python 3.7.3中,第二个版本略微更快。


对于Python 3,您应该将map内的list移到map外。您还可以通过使用b.append(n&1)而不是b = [n & 1] + b来获得一些性能优势。不幸的是,在我的情况下,“bits2”选项比纯版本快10倍。 - Thomas Ahle
@ThomasAhle:谢谢,已经编辑了“bits2”版本。在py3中它稍微快一点,但不如10倍快。 - georg

3

首先将数字转换为二进制,然后转换为字符串:

str(bin(7))
'0b111' #note the 0b in front of the binary number

接下来,从字符串中删除0b

str(bin(7))[2:]
'111'

最后,我们使用列表推导式从字符串中创建一个整数列表,它的形式大致如下:

[expr for i in iterable]
[int(i) for i in str(bin(x))[2:]]

3

map(int, list(bin((1<<8)+x))[-4:]) 这样的表达式会以列表的形式给出一个数字的低4位。(编辑:更简洁的形式为map(int,bin(x)[2:].zfill(4)); 请参见下文。) 如果您知道要显示的位数,将[-4:]中的4替换为该数字;如果需要,将(1<<8) 中的8改为更大的数字。例如:

>>> x=0b0111
>>> map(int,list(bin((1<<8)+x))[-4:])
[0, 1, 1, 1]
>>> x=37; map(int,list(bin((1<<8)+x))[-7:])
[0, 1, 0, 0, 1, 0, 1]
>>> [int(d) for d in bin((1<<8)+x)[-7:]]
[0, 1, 0, 0, 1, 0, 1]

上面的最后一个示例展示了一种使用map和list的替代方法。以下示例展示了获取前导零稍微更加简单的形式。在这些形式中,将期望的最小位数的数字8替换即可。
>>> x=37; [int(d) for d in bin(x)[2:].zfill(8)]
[0, 0, 1, 0, 0, 1, 0, 1]
>>> x=37; map(int,bin(x)[2:].zfill(8))
[0, 0, 1, 0, 0, 1, 0, 1]
>>> x=37; map(int,bin(x)[2:].zfill(5))
[1, 0, 0, 1, 0, 1]
>>> x=37; map(lambda k:(x>>-k)&1, range(-7,1))
[0, 0, 1, 0, 0, 1, 0, 1]

3

已更新为f-String:

x = 0b0111
y = [int(i) for i in f'{x:04b}']

y = [0, 1, 1, 1]

或者:

x = 0b0111 # binary representation of int 7
n_bits = 4 # desired bits' len
y = [int(i) for i in f'{x:0{n_bits}b}']

将生成一个最小长度为n位的列表,并在列表前面填充0。


2
如果比特长度固定为4,有两种解决方案:
[int(i) for i in '{0:04b}'.format(0b0111)]

或者使用 NumPy,

import numpy as np
[int(i) for i in np.binary_repr(0b0111, 4)]

0

检查这种简单的方法...针对这个特定的场景

In [41]: x=0b0111

In [42]: l = [0,0,0,0]

In [43]: counter = -1

In [44]: for i in str(bin(x))[2:]:
   ....:     l[counter] = i
   ....:     counter = counter -1
   ....:

In [45]: l
Out[45]: [0, '1', '1', '1']

0
c=[]
for i in bin(7)[2:]: 
        c.append(int(i)) #turning string "111", to 111
if len(c)==3:
    c.insert(0,0)
print(c)

# binary digit 7 produces '0b111' by this slicing[2:], result get '111'

所以如果列表c中的元素是3,则首先插入0。


1
请同时发布一些答案解释。 - Coding Mash

0

给定一个数字 value 和表示它的位数 width

string = format(value, '0{}b'.format(width))
binary_list = [0 if c == '0' else 1 for c in string]

这比 binary_list = [int(c) for c in string] 快了三分之一。


0

这里有一个简单的一行代码,不需要字符串解析:

[x >> bin_idx & 1 for bin_idx in reversed(range(x.bit_length()))]

我相信这比其他在这里发布的答案要快一些。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接