【问题标题】:How to select specific item from cartesian product without calculating every other item如何从笛卡尔积中选择特定项目而不计算所有其他项目
【发布时间】:2012-04-14 06:04:34
【问题描述】:

我基本上相信这个问题有一个答案,但我这辈子都不知道该怎么做。

假设我有三套:

A = [ 'foo', 'bar', 'baz', 'bah' ]
B = [ 'wibble', 'wobble', 'weeble' ]
C = [ 'nip', 'nop' ]

而且我知道如何计算笛卡尔/叉积,(在这个网站和其他地方到处都有它的介绍)所以我不会在这里讨论。

我正在寻找的是一种算法,它允许我从笛卡尔积中简单地选择一个特定项目生成整个集合或迭代直到我到达第 n 个项目。

当然,我可以轻松地为这样的小示例集进行迭代,但我正在处理的代码将使用更大的集。

因此,我正在寻找一个函数,我们称之为'CP',其中:

CP(1) == [ 'foo', 'wibble', 'nip' ]
CP(2) == [ 'foo', 'wibble', 'nop' ]
CP(3) == [ 'foo', 'wobble', 'nip' ]
CP(4) == [ 'foo', 'wobble', 'nop' ]
CP(5) == [ 'foo', 'weeble', 'nip' ]
CP(6) == [ 'foo', 'weeble', 'nop' ]
CP(7) == [ 'bar', 'wibble', 'nip' ]
...
CP(22) == [ 'bah', 'weeble', 'nop' ]
CP(23) == [ 'bah', 'wobble', 'nip' ]
CP(24) == [ 'bah', 'wobble', 'nop' ]

答案是在 O(1) 时间内产生的,或多或少。

我一直认为应该可以(哎呀,甚至很简单!)计算我想要的 A、B、C 中元素的索引,然后简单地从原始数组中返回它们,但是到目前为止,我试图使这项工作正常进行的尝试没有奏效。

我正在使用 Perl 进行编码,但我可以轻松地从 Python、JavaScript 或 Java(可能还有其他一些)移植解决方案

【问题讨论】:

标签: algorithm perl math cartesian-product cross-product


【解决方案1】:

可能的组合数由下式给出

N = size(A) * size(B) * size(C)

您可以通过索引i 索引所有项目,范围从0N(不包括)通过

c(i) = [A[i_a], B[i_b], C[i_c]]

在哪里

i_a = i/(size(B)*size(C)) 
i_b = (i/size(C)) mod size(B)
i_c = i mod size(C)

(假设所有集合都可以从零开始索引,/ 是整数除法)。

为了获得您的示例,您可以将索引移动 1。

【讨论】:

    【解决方案2】:

    我制作了霍华德答案的 python 版本。如果您认为可以改进,请告诉我。

    def ith_item_of_cartesian_product(*args, repeat=1, i=0):
        pools = [tuple(pool) for pool in args] * repeat   
        len_product = len(pools[0])
        for j in range(1,len(pools)):
            len_product = len_product * len(pools[j])
        if n >= len_product:
            raise Exception("n is bigger than the length of the product")
        i_list = []
        for j in range(0, len(pools)):
            ith_pool_index = i
            denom = 1
            for k in range(j+1, len(pools)):
                denom = denom * len(pools[k])
            ith_pool_index = ith_pool_index//denom
            if j != 0:
                ith_pool_index = ith_pool_index % len(pools[j])
            i_list.append(ith_pool_index)
        ith_item = []
        for i in range(0, len(pools)):
            ith_item.append(pools[i][i_list[i]])
        return ith_item
    

    【讨论】:

      【解决方案3】:

      这是基于霍华德回答的更短的 Python 代码:

      import functools
      import operator
      import itertools
      
      def nth_product(n, *iterables):
          sizes = [len(iterable) for iterable in iterables]
          indices = [
              int((n/functools.reduce(operator.mul, sizes[i+1:], 1)) % sizes[i])
              for i in range(len(sizes))]
          return tuple(iterables[i][idx] for i, idx in enumerate(indices))
      

      【讨论】:

        猜你喜欢
        • 2020-05-02
        • 1970-01-01
        • 2011-03-24
        • 2017-03-07
        • 2021-11-19
        • 1970-01-01
        • 1970-01-01
        • 2011-01-26
        • 2017-12-14
        相关资源
        最近更新 更多