如何在笛卡尔积中生成下一个元组?

时间:2016-10-15 21:45:13

标签: algorithm combinatorics cartesian-product

我有一个n元组x = (x[0], .., x[n-1]),其中元组的每个成员都来自一个不同的,有序的集S[i],而x[i] \in S[i]。集合S[i]都有不同的基数N[i]。我想知道如何在集合S[i]的情况下以词法顺序生成下一个元组。

示例:

S[0] = {0,1,2}
S[1] = {1,2,3,4}
S[2] = {8,9,7}

x = {2,2,7}
xnext = {2,3,8}
xnextnext = {2,3,9}

这不一定非常有效,只是根据当前元组元素和集合的封闭形式。如果它更容易,那就相当于将n元组视为集合中的索引。

2 个答案:

答案 0 :(得分:0)

对于给定的元组,您可以将元组的元素映射到每组S中的各自索引,然后尝试"递增"由此元组索引表示的mixed-radix数字。然后,取增加的"数字"并将其映射回元素元组。这是Python中的概念验证:

def next_tuple(x, S):
    assert len(x) == len(S)
    assert all(element in set_ for element, set_ in zip(x, S))

    # compute the bases for our mixed-radix system
    lengths = [len(set_) for set_ in S]
    # convert tuple `x` to a mixed-radix number
    indices = [set_.index(element) for element, set_ in zip(x, S)]

    # try to increment, starting from the right
    for k in reversed(range(len(indices))):
        indices[k] += 1

        if indices[k] == lengths[k]: 
            # case 1: we have a carry, rollover this index and continue
            indices[k] = 0
        else:
            # case 2: no carry, map indices back to actual elements and return
            return [set_[index] for index, set_ in zip(indices, S)]

    # we have gone through each position and still have a carry.
    # this means the "increment" operation overflowed, and there
    # is no "next" tuple.
    return None


S = [[0, 1, 2], [1, 2, 3, 4], [8, 9, 7]]

print("next tuple after {} is {}".format([2, 2, 7], next_tuple([2, 2, 7], S)))
print("all tuples in order:")

x = [0, 1, 8]

while x is not None:
    print(x)
    x = next_tuple(x, S)

最后请注意,如果您需要按顺序枚举整个笛卡尔积,则使用直接算法更简单,而不是重复使用next_tuple,每次都必须重新计算索引。

答案 1 :(得分:0)

我使用这个伪代码让它工作:

# x = [2,2,7]
sets = [[0,1,2], [1,2,3,4], [8,9,7]]
def next_tuple(x):
    for i, el in enumerate(x):
        if(i < len(sets[i]) - 1):
            x[i] = sets[i, sets[i].index(x[i])+1] // requires lists to have unique elements
            return x
        else :
            x[i] = sets[i,0]

基本上你从元组中扫描一个字符,如果它可以递增,则递增它。如果没有,请将其设置为0并转到下一个字符。