我有一个很长的一维整数 1 和 0 列表,代表 8 位二进制字节。从中创建包含整数字节的新列表的简洁方法是什么。
我熟悉 C,但对 Python 不熟悉,所以我按照使用 C 的方式对其进行了编码:一个遍历每一位的复杂结构。然而,我知道 Python 相对于 C 的全部意义在于这些事情通常可以紧凑而优雅地完成,我应该学习如何做到这一点。也许使用列表理解?
这行得通,但对于更“Pythonic”方式的建议将不胜感激:
#!/usr/bin/env python2
bits = [1,0,0,1,0,1,0,1,0,1,1,0,1,0,1,1,1,1,1,0,0,1,1,1]
bytes = []
byt = ""
for bit in bits:
byt += str(bit)
if len(byt) == 8:
bytes += [int(byt, 2)]
byt = ""
print bytes
$ bits-to-bytes.py
[149, 107, 231]
最佳答案
您可以将列表分成 8 个元素的 block 并将子元素映射到 str:
[int("".join(map(str, bits[i:i+8])), 2) for i in range(0, len(bits), 8)]
你可以把它分成两部分映射和连接一次:
mapped = "".join(map(str, bits))
[int(mapped[i:i+8], 2) for i in range(0, len(mapped), 8)]
或者用iter 借用grouper recipe在 itertools 中:
it = iter(map(str, bits))
[int("".join(sli), 2) for sli in zip(*iter([it] * 8))]
iter(map(str, bits))
将 bits 的内容映射到 str 并创建一个 iterator , zip(*iter([it] * 8))
将元素分组为 8 个子元素组。
每个 zip(*iter..
从我们的迭代器中消耗八个子元素,所以我们总是得到顺序组,它与第一个代码中的切片逻辑相同,我们只是避免了切片的需要。
正如 Sven 评论的那样,对于不能被 n
整除的列表,您将使用与原始代码类似的 zip 丢失数据,您可以调整我链接的石斑鱼食谱来处理这些情况:
from itertools import zip_longest # izip_longest python2
bits = [1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1,1,0]
it = iter(map(str, bits))
print( [int("".join(sli), 2) for sli in izip_longest(*iter([it] * 8),fillvalue="")])
[149, 107, 231, 2] # using just zip would be [149, 107, 231]
fillvalue=""
意味着我们用空字符串填充奇数长度组,这样我们仍然可以调用 int("".join(sli), 2)
和在采用 3 * 8
block 后得到 1,0
的正确输出。
在你自己的代码中 bytes += [int(byt, 2)]
可以简单地变成 bytes.append(int(byt, 2))
关于Python 位列表到字节列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32284940/