python - 将整数转换为半字节,`to_bytes()`?
问题描述
我有一个整数列表:
var = [1, 5, 4, 17, 231, 89]
如果我想将其转换为字节列表,我可以这样做:
[(i).to_bytes(1, byteorder='big') for i in var]
由于 in 中的每个值var
都小于 256,因此每个整数可以容纳一个字节。但是,如果我有另一个清单,请说:
var = [1, 2, 15, 12]
这可以将一个整数放入半个字节,或者更准确地说是我正在寻找的,每个字节适合两个整数。
如果可能,我如何指定将两个整数组合成一个字节,既往又往?
如下所示:
var1 = [1, 5, 4, 17, 231, 89]
var2 = [1, 2, 15, 12]
def foo(var):
if max(var) < 2**4:
num_bytes = 0.5
elif max(var) < 2**8:
num_bytes = 1
elif max(var) < 2**16:
num_bytes = 2
if num_bytes >= 1:
return [(i).to_bytes(num_bytes, byteorder='big') for i in var], num_bytes
elif num_bytes = 0.5:
# convert var to list of nybbles
# combine two nybbles to a byte
# create list of bytes (length is half length of var)
# return it and num_bytes
def unfoo(var, num_bytes):
if num_bytes >= 1:
print([int.from_bytes(i, 'big') for i in var])
elif num_bytes = 0.5:
# print original list of integers again
我想将整数列表转换为字节列表,但是如果可以将两个 nybbles 拟合为一个字节,然后再进行转换。
期望的结果是:
a, b = foo(var1)
unfoo(a, b) # prints [1, 5, 4, 17, 231, 89]
a, b = foo(var2)
unfoo(a, b) # prints [1, 2, 15, 12]
我不想要一个最小位数的列表来代表一个数字。请注意max(list)
:如果列表中的所有值都可以是 8 位,则将其调整为 8 位;如果所有值都可以是 16 位,则适合 16 位;如果所有值都可以是 nybble,则将两个 nybble 对组成一个字节列表。
基本上,如果我有两个整数可以分别放入一个 nybble 中,我如何将它们连接成一个字节?如果我知道需要将字节拆分为两个,我该如何拆分?我总是可以假设原始列表可以被 2 整除。
解决方案
您需要弄清楚一个字节可以容纳多少个数字。然后,您需要将每个数字移动正确的数量并创建一个包含组合数字的新列表。假设你可以在一个字节中放入两个数字,你会得到new_number = (old_num1 << 4) + old_num2
def foo(var):
num_bytes = math.ceil(1 + max(math.log2(x) for x in var)) / 8
if num_bytes >= 1:
num_bytes = int(num_bytes)
return [(i).to_bytes(num_bytes, byteorder='big') for i in var], num_bytes
elif num_bytes == 0.5:
shift_bits = 4 # or generally, int(num_bytes * 8)
new_list = [(a << shift_bits) + b for a, b in zip(var[::2], var[1::2])]
return [(i).to_bytes(1, byteorder='big') for i in new_list], num_bytes
要unfoo
,您需要执行此操作的逆操作:当 时,我们可以找到您在函数num_bytes < 1
中移动的位数。foo()
按照与前面的解释相同的名称,并给出new_number
,我们可以得到old_num2
作为最低有效四位(由 找到new_number & mask
)并且old_num1
是最高有效四位(由 找到new_number >> shift_bits
)
def unfoo(var, num_bytes):
if num_bytes >= 1:
return [int.from_bytes(i, 'big') for i in var]
elif num_bytes == 0.5:
new_list = [int.from_bytes(i, 'big') for i in var]
ret = []
shift_bits = 4 # in general: int(num_bytes * 8)
mask = int(2**shift_bits - 1)
for i in new_list:
b = i & mask
a = (i >> shift_bits) & mask
ret.append(a)
ret.append(b)
return ret
检查这是否有效:
var1 = [1, 5, 4, 17, 231, 89]
var2 = [1, 2, 15, 12]
a, b = foo(var1)
c = unfoo(a, b) # prints [1, 5, 4, 17, 231, 89]
print(var1)
print(c)
a2, b2 = foo(var2)
c2 = unfoo(a2, b2) # prints [1, 2, 15, 12]
print(var2)
print(c2)
给出预期的输出:
[1, 5, 4, 17, 231, 89]
[1, 5, 4, 17, 231, 89]
[1, 2, 15, 12]
[1, 2, 15, 12]
推荐阅读
- ios - 视图控制器不尊重“largeTitleDisplayMode”
- google-sheets - Filter function for Google Sheets - dynamic cell reference
- python - 当切换到其他分支或从终端运行黑色时,Vim 不显示更改
- kubernetes - 遵循使用 Lets Encrypt 的教程后,无法在 EKS 的应用程序网关中公开 HTTPS
- pine-script - 我想为买入条件编写代码:最近 5 个柱的收盘价一直在上涨
- html - 无法向列表元素添加工具提示
- python - pytest:新组件的集成步骤和测试
- java - 尝试导入 Python 库时出现 Jython 错误
- laravel - Laravel 表单验证,如何将 alpha_dash 与斜线结合使用?
- excel - 从列中选择的随机数