序列的有序笛卡尔积

时间:2014-08-19 19:24:06

标签: arrays sorting product lazy-evaluation cartesian

efficient sorted Cartesian product of 2 sorted array of integers中,建议使用惰性算法为两个排序的整数数组生成有序的笛卡尔积。

我很想知道这个算法是否有更多数组的推广。

例如说我们有5个已排序的双精度数组

(0.7,0.2,0.1)

(0.6,0.3,0.1)

(0.5,0.25,0.25)

(0.4,0.35,0.25)

(0.35,0.35,0.3)

我有兴趣生成订购的笛卡尔积,而无需计算所有可能的组合。

欣赏有关可能的懒惰笛卡尔积算法如何扩展到超过2的维度的任何想法。

2 个答案:

答案 0 :(得分:2)

此问题似乎是统一成本搜索的枚举实例(请参阅例如https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm)。您的状态空间由指向已排序数组的当前索引集定义。后继函数是每个数组的可能索引增量的枚举。对于5个数组的给定示例,初始状态为(0,0,0,0,0)。

没有目标状态检查功能,因为我们需要经历所有可能性。如果对所有输入数组进行排序,则保证对结果进行排序。

假设我们有m个长度为n的数组,那么这个方法的复杂性是O((n ^ m).log(n(m-1))。

以下是python中的示例实现:

from heapq import heappush, heappop

def cost(s, lists):
    prod = 1
    for ith, x in zip(s, lists):
        prod *= x[ith]
    return prod

def successor(s, lists):
    successors = []
    for k, (i, x) in enumerate(zip(s, lists)):
        if i < len(x) - 1: 
            t = list(s)
            t[k] += 1
            successors.append(tuple(t))
    return successors

def sorted_product(initial_state, lists):    
    fringe = []
    explored = set()
    heappush(fringe, (-cost(initial_state, lists), initial_state))
    while fringe:
        best = heappop(fringe)[1]
        yield best
        for s in successor(best, lists):
            if s not in explored:
                heappush(fringe, (-cost(s, lists), s))
                explored.add(s)

if __name__ == '__main__':
    lists = ((0.7, 0.2, 0.1),
             (0.6, 0.3, 0.1),
             (0.5, 0.25, 0.25),
             (0.4, 0.35, 0.25),
             (0.35, 0.35, 0.3))
    init_state = tuple([0]*len(lists))
    for s in sorted_product(init_state, lists):
        s_output = [x[i] for i, x in zip(s, lists)]
        v = cost(s, lists)
        print '%s %s \t%s' % (s, s_output, cost(s, lists))

答案 1 :(得分:0)

所以,如果你有A(A1,...,An)和B(B1,...,Bn)。

A&lt; B当且仅当

A1 * ... * An&lt; B1 * ... * Bn

我假设每个值都是正数,因为如果我们允许负数,那么:

( - 50,-100,1)&gt; (1,2,3)

为-50 *( - 100)* 1 = 5000&gt; 6 = 1 * 2 * 3

即使没有负值,问题仍然相当复杂。您需要一个包含数据结构的解决方案,其深度为k。如果(A1,...,Ak)&lt; (B1,...,Bk),那么我们可以假设在其他维度上,(A1,...,Ak,... An)的组合可能小于(B1,..., Bk,...,Bn)。结果,只要不是这样,情况就会超过概率,因此那些将是规则的例外。数据结构应该成立:

  • ķ
  • 分别为A和B的前k个元素
  • 来自规则的例外的描述

对于任何此类例外情况,可能有(C1,...,Ck)的组合大于(B1,...,Bk),但是(C1,..., Ck)可能仍然具有使用其他维度的值的组合,其中(A1,...,Ak)的规则的例外<1。 (C1,...,Ck)可能仍然存在。

所以,如果你已经知道(A1,...,Ak)&lt; (B1,...,Bk),那么首先你必须通过找到前面的l维来检查是否存在异常,其中选择A的最大可能值和B的最小可能值。如果存在,那么你应该找到异常开始的位置(哪个维度,哪个索引)。这将描述异常。当您发现异常时,您知道(A1,...,Ak,...,Al)&gt;的组合。 (B1,...,Bk,...,Bl),所以规则是A大于B,当B变大于A时会出现异常。

为了反映这一点,数据结构如下所示:

class Rule {
    int k;
    int[] smallerCombinationIndexes;
    int[] biggerCombinationIndexes;
    List<Rule> exceptions;
}

每当您发现规则的例外情况时,都会根据先前的知识生成异常。毋庸置疑,复杂性大大增加,但问题是您有规则例外,例外例外等等。当前的方法会告诉你,如果你取两个随机点A和B,A是否小于B,它也会告诉你,如果你采用(A1,...,Ak)和(B1 ,. ..,Bk),那么(A1,...,Ak)和(B1,...,Bk)的比较结果会发生变化的关键指标是什么。根据您的确切需求,这个想法可能已经足够或者可能需要扩展。因此,您的问题的答案是:是的,您可以扩展惰性算法以处理更多维度,但您需要处理规则的例外以实现这一点。