我有一组任意大小的二进制标志作为数字int
。
例如,数字“18”< 2**5
=> 最少 5 个标志。
我需要使用相当复杂的方案找到设置标志的所有组合。我宁愿举一个例子并展示我想要得到的东西。我想编写一个生成器,它以数字作为输入并仅返回该数字*的设置位的所有组合。例如,考虑数字 18:
>>> bin(18)
'0b10010'
我想制作一个将返回以下内容的生成器:
yield [True, False, False, True, False] # исходное число
yield [False, False, False, True, False] # первый флаг установлен в 'False'
yield [True, False, False, False, False] # только второй флаг установлен в 'False'
yield [False, False, False, False, False] # оба флага установлены в `False`
- 只能更改原始数字中的单位。
- 标志的排序顺序很重要;标志从左到右排序。
- 生成的序列不包含重复。
- 两个标志被关闭的组合必须始终出现在仅一个标志被关闭的任何组合之后。那是
[True, True, False, True]
比
[True, False, False, True]
和什么
[True, True, False, False]
因此,生成器必须首先吐出最接近原始序列的组合。
如果返回数字而不是列表,我会很高兴int
。以我为例:
yield 18
yield 2
yield 16
yield 0
为什么这是必要的?我正在寻找一组输入数据的最接近的组合(在 Levenshtein 度量中(没有邻居排列))来训练神经网络来预测某个集合。标志指示源数据中是否存在列。我通过谓词运行结果数字来了解它是否适合我。
CPU_Bound 算法(要求渐进复杂度)。
最后,根据@MBo 和@Stanislav Volodarskiy 的答案,我使用了以下代码(欢迎批评!):
from itertools import combinations
def gen_submasks(n:int):
def gen_bases(n:int):
while n > 0:
yield (base := 1 << n.bit_length() - 1)
n = n ^ base
# alternative syntax:
# base = 1 << n.bit_length() - 1
# yield base
# n ^= base
for count in range(n.bit_count()):
for combination in combinations(gen_bases(n), count):
yield n - sum(combination)
yield 0
def main():
n = 41
for submask in gen_submasks(n):
print(bin(submask)[2:].zfill(n.bit_length()))
main()
# 101001
# 001001
# 100001
# 101000
# 000001
# 001000
# 100000
# 000000
子掩码枚举:
选择所有设置位作为元组。然后我们对位的子集进行排序,降低它们的功率。子集由位组装而成 - 这是我们需要的掩码: