编码与数学之循环
编写代码过程中,经常会遇到一些奇奇怪怪的需求,有一些问题一眼看上去很复杂,但是实际上通过特定的数学运算过程就可以很方便的实现。这里记录几种比较典型的案例。
取模运算
取模运算最大的特点就是随着被除数的变化,输出的结果是单项循环变化的,即 “123123123”。
一个典型的例子是:
samples = ["00", "01", "02", "10", "11", "12", "20", "21", "22"]
sample_infos = [(s, i % 3, 3) for i, s in enumerate(samples)]
print(sample_infos)
# [('00', 0, 3), ('01', 1, 3), ('02', 2, 3), ('10', 0, 3), ('11', 1, 3), ('12', 2, 3), ('20', 0, 3), ('21', 1, 3), ('22', 2, 3)]
length_of_group = 10
curr_idx = base_idx = 4 # 基础索引值
is_forward = True
results = []
for i in range(length_of_group):
x, idx, length = sample_infos[curr_idx]
group_start_idx = curr_idx - idx
curr_idx = group_start_idx + (idx + 1) % length
results.append(x)
print(results)
# ['11', '12', '10', '11', '12', '10', '11', '12', '10', '11']
这段代码摘自一段训练视频模型的代码,用于在各个视频序列内部抽取连续的几帧作为输出。当抽到结尾之后,会从序列的开头继续抽取。
指数运算
指数运算的性质则需要看具体的底数。在数据循环时,我们可能需要实现类似反射的形式,这种情况下可以使用以 -1 为底数的指数来实现,即“1232123”这种形式。
一个典型的例子是:
samples = ["00", "01", "02", "10", "11", "12", "20", "21", "22"]
sample_infos = [(s, i % 3, 3) for i, s in enumerate(samples)]
print(sample_infos)
# [('00', 0, 3), ('01', 1, 3), ('02', 2, 3), ('10', 0, 3), ('11', 1, 3), ('12', 2, 3), ('20', 0, 3), ('21', 1, 3), ('22', 2, 3)]
length_of_group = 10
curr_idx = 4 # 基础索引值
is_forward = True
results = []
for i in range(length_of_group):
x, idx, length = sample_infos[curr_idx]
if idx == length - 1 and is_forward:
is_forward = False
elif idx == 0 and not is_forward:
is_forward = True
curr_idx -= (-1) ** int(is_forward)
results.append(x)
print(results)
# ['11', '12', '11', '10', '11', '12', '11', '10', '11', '12']
这段代码同样可以用于训练视频模型,在各个视频序列内部抽取连续的几帧作为输出,只是在结尾的时候,抽帧顺序会返回来,若是片段要求够长,到了开头还会继续折回来。