【问题标题】:How to generate the next tuple in a Cartesian product?如何在笛卡尔积中生成下一个元组?
【发布时间】:2017-02-25 03:32:16
【问题描述】:

我有一个 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 元组视为集合中的索引。

【问题讨论】:

    标签: algorithm combinatorics cartesian-product


    【解决方案1】:

    对于给定的元组,您可以将元组的元素映射到每组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 更简单。

    【讨论】:

    • 我想我做了类似的事情,虽然我以前从未使用过 zip()。检查我的答案,看看是否有意义
    【解决方案2】:

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

    # 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 并转到下一个字符。

    【讨论】:

    • 这将有两个变化:1)你需要首先增加最右边的位置(所以你需要像for i from len(x)-1 down to 0这样的伪代码而不是for i, el in enumerate(x)); 2)if 语句需要检查元素的索引是否可以增加,而不是i(因此,您可以使用if i &lt; len(sets[i]) - 1 而不是if sets[i].index(x[i]) &lt; len(sets[i]) - 1。通过这些更改,它将是正确的,并且有一些小的语法更改它甚至会是有效的 Python 代码。
    • 感谢您的更改,我知道我翻译了部分错误。同样正确的是,我必须进行 N-i 索引以保留字典顺序。如果您有兴趣,我会用实际语言 (LabVIEW) 发布代码 sn-p。
    猜你喜欢
    • 2016-10-08
    • 2021-05-06
    • 2011-12-26
    • 2016-05-07
    • 1970-01-01
    • 2015-11-08
    • 2012-11-18
    • 2011-03-01
    • 2022-11-17
    相关资源
    最近更新 更多