Python 位列表到字节列表

标签 python list parsing binary

我有一个很长的一维整数 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/

相关文章:

python - 如何检查列表中是否出现两个列表项的任意组合

python - 如何创建一个带有负索引的 python 列表

java - 解析 xml 响应并将其显示到黑莓主屏幕

c++ - 如何在 linux 终端中处理带有负号 (-) 的 C++ 命令行参数?

c - *int 是什么意思?

python - plt.savefig 在 Python 中生成空白图形

python - 如何更改 Python 中数组打印的行为?

python - 使用 pyodbc 从 Python 到 Access 2016 的 ODBC 连接失败

python - Django 中的 ModuleNotFound 错误。无法解决错误

Python-获取列表中少数类的百分比