Skip to the content.

Python中使用序列解决不确定循环层数的遍历问题


Contact me:

Blog -> https://cugtyt.github.io/blog/index
Email -> cugtyt@qq.com
GitHub -> Cugtyt@GitHub


如果遇到循环层数是变量的情况如何解决?

问题引入,有属性集:

属性 属性类别 数据标号
r1 0 1,2,3,4
r1 1 5,6,7,8,9,10
r2 0 1,8,9,10
r2 1 2,3,7
r2 2 4,5,6
r3 0 1,3,5,7,9
r3 1 2,4,6,8,10

根据属性的类别可以求出初等集:

r1,r2,r3 数据标号
0,0,0 1
0,0,1 None
0,1,0 3
0,1,1 2
0,2,0 None
0,2,1 4
1,0,0 9
1,0,1 8,10
1,1,0 7
1,1,1 None
1,2,0 5
1,2,1 6

一个最直观的解法是:

data = [
    [set([1,2,3,4]), set([5,6,7,8,9,10])],
    [set([1,8,9,10]), set([2,3,7]), set([4,5,6])],
    [set([1,3,5,7,9]), set([2,4,6,8,10])]
]

# len(r1)是r1的类别数,2
# 后面类似
for i in range(len(r1)):
    for j in range(len(r2)):
        for k in range(len(r3)):
            # 求三个属性集合的交集
            print(data[0][i] & data[1][j] & data[2][k])

对于上面的确定问题来说,这个方法已经足够,但是考虑到更为一般的情况,属性个数是不确定的,可能有很多个,这就意味着for将会有很多层,这个不确定循环层数的问题导致上面的思路将无法解决问题。

因此,我们需要换一个思路,由于不能动态决定循环层数,我们就不采用for循环的做法,思路简单描述为:

首先我们生成一个长度为属性长度的索引:

# index为[0]*属性个数,在上面的例子中为[0,0,0]
index = [0] * len(data)
# index_max为index的最大值,在上面的例子中为[2,3,2]
index_max = [len(d) for d in data]

然后读取index的初等集为:

def get(data, index):
    out = data[0][index[0]]
    for i in range(1, len(index)):
        out = out & data[i][index[i]]
    return out

更新index,可以获取新的index:

def add(index, index_max):
    for i in range(1, len(index) + 1):
        index[-i] += 1
        if index[-i] < index_max[-i]:
            break
        index[-i] %= index_max[-i]

把上面的思路结合起来就是:

data = [
    [set([1,2,3,4]), set([5,6,7,8,9,10])],
    [set([1,8,9,10]), set([2,3,7]), set([4,5,6])],
    [set([1,3,5,7,9]), set([2,4,6,8,10])]
]

index = [0] * len(data)
index_max = [len(d) for d in data]
steps = sum(index_max)

def get(data, index):
    out = data[0][index[0]]
    for i in range(1, len(index)):
        out = out & data[i][index[i]]
    return out


def add(index, index_max):
    for i in range(1, len(index) + 1):
        index[-i] += 1
        if index[-i] < index_max[-i]:
            break
        index[-i] %= index_max[-i]

out = []
for i in range(0, steps):
    out.append(get(data, index))
    add(index, index_max)

将这个算法思路做个比喻的话,就是index就是时间值,index_max是时间的最大值,steps是从开始到最大值所需要的次数,每次add就是增加时间值,每次get就是获取在index时间值时的一个初等集,当我们add够steps次,那么就完成了对初等集的完整获取,out就是最后的结果。

这样我们通过可变长度的序列化解了不确定循环层数的问题,所有类似需要不确定循环次数的问题可以借鉴该思路转化求解。