【问题标题】:Sorted tuples from cartesian product of lists从列表的笛卡尔积中排序的元组
【发布时间】:2012-05-31 15:12:48
【问题描述】:

我有列表字典,如下所示:

D = {'x': [15, 20],
     'y': [11, 12, 14, 16, 19],
     'z': [7, 9, 17, 18]}

我想一次取 3 个键(我将使用 itertools.permutations),然后计算我可以从每个列表中取一个元素并对结果进行排序的所有方式。

对于上面显示的三个键,我会得到 2:

(15, 16, 17)
(15, 16, 18)

显然,我可以对字典值进行笛卡尔积,然后计算排序的值:

answer = 0
for v_x, v_y, v_z in product(D['x'], D['y'], D['z']):
    if v_x < v_y < v_z:
        answer += 1

但是,我可以做得更好吗?此解决方案不适用于键的数量和作为值的列表的长度。我尝试了几行毫无结果的查询,但我怀疑我可能不得不利用键映射到列表值的方式。但是,我认为值得看看是否有一个我可以使用的解决方案,而无需重新执行程序的其余部分。

ETA:这是一个更大的例子。

D = {'a': [15, 20],
     'b': [8],
     'c': [11, 12, 14, 16, 19],
     'd': [7, 9, 17, 18],
     'e': [3, 4, 5, 6, 10, 13],
     'f': [2],
     'g': [1]}

有 14 个有效答案:

(8, 9, 10)  (8, 9, 13) (8, 11, 13) (8, 12, 13) (8, 11, 17) (8, 11, 18) (8, 12, 17) (8, 12, 18) (8, 14, 17) (8, 14, 18) (8, 16, 17) (8, 16, 18) (15, 16, 17) (15, 16, 18)

【问题讨论】:

  • 如果您只是对计数感兴趣,则无需生成所有排列。
  • 乔尔,感谢您的来信。你的意思是键的排列吗?如果是这样,我不太关注你。也就是说,我有大约 360 个键,每个键都有自己的列表(碰巧一个键的列表中的元素不会出现在任何其他键的列表中)。如何避免产生排列?

标签: python combinatorics dynamic-programming


【解决方案1】:

递归解:

In [9]: f??
Definition: f(lists, triple)
Source:
def f(lists, triple):
    out = set()
    for i in range(len(lists)):
        for x in lists[i]:
            if len(triple) == 2 and triple[1] < x:
                out.add(triple + (x,))
            elif len(triple) == 0 or triple[0] < x:
                for j in range(i+1, len(lists)):
                    out.update(f(lists[j:], triple + (x,)))
    return out

输入:

In [10]: lists
Out[10]: 
[[15, 20],
 [8],
 [11, 12, 14, 16, 19],
 [7, 9, 17, 18],
 [3, 4, 5, 6, 10, 13],
 [2],
 [1]]

输出:

In [11]: out = f(lists, ())

In [12]: len(out)
Out[12]: 14

In [13]: out
Out[13]: 
set([(8, 9, 10),
     (8, 12, 18),
     (8, 11, 13),
     (8, 16, 17),
     (15, 16, 17),
     (8, 12, 17),
     (8, 14, 18),
     (15, 16, 18),
     (8, 11, 17),
     (8, 9, 13),
     (8, 14, 17),
     (8, 11, 18),
     (8, 12, 13),
     (8, 16, 18)])

【讨论】:

    【解决方案2】:

    在您给出的示例中,所有字典列表都已预先排序,因此您可以在调用 itertools.product 之前自己进行一些排序以减少枚举数量:

    def count_sorted(x,y,z):
        from itertools import ifilter, product, imap
    
        _x = ifilter(lambda k: k<z[-1],x)
        _y = ifilter(lambda k: x[0]<k<z[-1],y)
        _z = ifilter(lambda k: k > x[0],z)
    
        return sum(imap(lambda t: t[0]<t[1]<t[2], product(_x,_y,_z)))
    
    
    D = {'a': [15, 20],
         'b': [8],
         'c': [11, 12, 14, 16, 19],
         'd': [7, 9, 17, 18],
         'e': [3, 4, 5, 6, 10, 13],
         'f': [2],
         'g': [1]}
    
    for key1,key2,key3 in itertools.permutations(D.keys(),3):
        print '[%s, %s, %s] has %i sorted combinations'%(key1,key2,key3,count_sorted(D[key1],D[key2],D[key3]))
    

    结果:

    [a, c, b] has 0 sorted combinations
    [a, c, e] has 0 sorted combinations
    [a, c, d] has 2 sorted combinations
    [a, c, g] has 0 sorted combinations
    [a, c, f] has 0 sorted combinations
    [a, b, c] has 0 sorted combinations
    [a, b, e] has 0 sorted combinations
    [a, b, d] has 0 sorted combinations
    [a, b, g] has 0 sorted combinations
    [a, b, f] has 0 sorted combinations
    [a, e, c] has 0 sorted combinations
    [a, e, b] has 0 sorted combinations
    [a, e, d] has 0 sorted combinations
    [a, e, g] has 0 sorted combinations
    [a, e, f] has 0 sorted combinations
    [a, d, c] has 2 sorted combinations
    [a, d, b] has 0 sorted combinations
    [a, d, e] has 0 sorted combinations
    [a, d, g] has 0 sorted combinations
    [a, d, f] has 0 sorted combinations
    [a, g, c] has 0 sorted combinations
    [a, g, b] has 0 sorted combinations
    [a, g, e] has 0 sorted combinations
    [a, g, d] has 0 sorted combinations
    [a, g, f] has 0 sorted combinations
    [a, f, c] has 0 sorted combinations
    [a, f, b] has 0 sorted combinations
    [a, f, e] has 0 sorted combinations
    [a, f, d] has 0 sorted combinations
    [a, f, g] has 0 sorted combinations
    [c, a, b] has 0 sorted combinations
    [c, a, e] has 0 sorted combinations
    [c, a, d] has 6 sorted combinations
    [c, a, g] has 0 sorted combinations
    [c, a, f] has 0 sorted combinations
    [c, b, a] has 0 sorted combinations
    [c, b, e] has 0 sorted combinations
    [c, b, d] has 0 sorted combinations
    [c, b, g] has 0 sorted combinations
    [c, b, f] has 0 sorted combinations
    [c, e, a] has 4 sorted combinations
    [c, e, b] has 0 sorted combinations
    [c, e, d] has 4 sorted combinations
    [c, e, g] has 0 sorted combinations
    [c, e, f] has 0 sorted combinations
    [c, d, a] has 8 sorted combinations
    [c, d, b] has 0 sorted combinations
    [c, d, e] has 0 sorted combinations
    [c, d, g] has 0 sorted combinations
    [c, d, f] has 0 sorted combinations
    [c, g, a] has 0 sorted combinations
    [c, g, b] has 0 sorted combinations
    [c, g, e] has 0 sorted combinations
    [c, g, d] has 0 sorted combinations
    [c, g, f] has 0 sorted combinations
    [c, f, a] has 0 sorted combinations
    [c, f, b] has 0 sorted combinations
    [c, f, e] has 0 sorted combinations
    [c, f, d] has 0 sorted combinations
    [c, f, g] has 0 sorted combinations
    [b, a, c] has 2 sorted combinations
    [b, a, e] has 0 sorted combinations
    [b, a, d] has 2 sorted combinations
    [b, a, g] has 0 sorted combinations
    [b, a, f] has 0 sorted combinations
    [b, c, a] has 8 sorted combinations
    [b, c, e] has 2 sorted combinations
    [b, c, d] has 8 sorted combinations
    [b, c, g] has 0 sorted combinations
    [b, c, f] has 0 sorted combinations
    [b, e, a] has 4 sorted combinations
    [b, e, c] has 8 sorted combinations
    [b, e, d] has 4 sorted combinations
    [b, e, g] has 0 sorted combinations
    [b, e, f] has 0 sorted combinations
    [b, d, a] has 4 sorted combinations
    [b, d, c] has 7 sorted combinations
    [b, d, e] has 2 sorted combinations
    [b, d, g] has 0 sorted combinations
    [b, d, f] has 0 sorted combinations
    [b, g, a] has 0 sorted combinations
    [b, g, c] has 0 sorted combinations
    [b, g, e] has 0 sorted combinations
    [b, g, d] has 0 sorted combinations
    [b, g, f] has 0 sorted combinations
    [b, f, a] has 0 sorted combinations
    [b, f, c] has 0 sorted combinations
    [b, f, e] has 0 sorted combinations
    [b, f, d] has 0 sorted combinations
    [b, f, g] has 0 sorted combinations
    [e, a, c] has 12 sorted combinations
    [e, a, b] has 0 sorted combinations
    [e, a, d] has 12 sorted combinations
    [e, a, g] has 0 sorted combinations
    [e, a, f] has 0 sorted combinations
    [e, c, a] has 44 sorted combinations
    [e, c, b] has 0 sorted combinations
    [e, c, d] has 44 sorted combinations
    [e, c, g] has 0 sorted combinations
    [e, c, f] has 0 sorted combinations
    [e, b, a] has 8 sorted combinations
    [e, b, c] has 20 sorted combinations
    [e, b, d] has 12 sorted combinations
    [e, b, g] has 0 sorted combinations
    [e, b, f] has 0 sorted combinations
    [e, d, a] has 28 sorted combinations
    [e, d, c] has 52 sorted combinations
    [e, d, b] has 4 sorted combinations
    [e, d, g] has 0 sorted combinations
    [e, d, f] has 0 sorted combinations
    [e, g, a] has 0 sorted combinations
    [e, g, c] has 0 sorted combinations
    [e, g, b] has 0 sorted combinations
    [e, g, d] has 0 sorted combinations
    [e, g, f] has 0 sorted combinations
    [e, f, a] has 0 sorted combinations
    [e, f, c] has 0 sorted combinations
    [e, f, b] has 0 sorted combinations
    [e, f, d] has 0 sorted combinations
    [e, f, g] has 0 sorted combinations
    [d, a, c] has 4 sorted combinations
    [d, a, b] has 0 sorted combinations
    [d, a, e] has 0 sorted combinations
    [d, a, g] has 0 sorted combinations
    [d, a, f] has 0 sorted combinations
    [d, c, a] has 18 sorted combinations
    [d, c, b] has 0 sorted combinations
    [d, c, e] has 4 sorted combinations
    [d, c, g] has 0 sorted combinations
    [d, c, f] has 0 sorted combinations
    [d, b, a] has 2 sorted combinations
    [d, b, c] has 5 sorted combinations
    [d, b, e] has 2 sorted combinations
    [d, b, g] has 0 sorted combinations
    [d, b, f] has 0 sorted combinations
    [d, e, a] has 8 sorted combinations
    [d, e, c] has 16 sorted combinations
    [d, e, b] has 0 sorted combinations
    [d, e, g] has 0 sorted combinations
    [d, e, f] has 0 sorted combinations
    [d, g, a] has 0 sorted combinations
    [d, g, c] has 0 sorted combinations
    [d, g, b] has 0 sorted combinations
    [d, g, e] has 0 sorted combinations
    [d, g, f] has 0 sorted combinations
    [d, f, a] has 0 sorted combinations
    [d, f, c] has 0 sorted combinations
    [d, f, b] has 0 sorted combinations
    [d, f, e] has 0 sorted combinations
    [d, f, g] has 0 sorted combinations
    [g, a, c] has 2 sorted combinations
    [g, a, b] has 0 sorted combinations
    [g, a, e] has 0 sorted combinations
    [g, a, d] has 2 sorted combinations
    [g, a, f] has 0 sorted combinations
    [g, c, a] has 8 sorted combinations
    [g, c, b] has 0 sorted combinations
    [g, c, e] has 2 sorted combinations
    [g, c, d] has 8 sorted combinations
    [g, c, f] has 0 sorted combinations
    [g, b, a] has 2 sorted combinations
    [g, b, c] has 5 sorted combinations
    [g, b, e] has 2 sorted combinations
    [g, b, d] has 3 sorted combinations
    [g, b, f] has 0 sorted combinations
    [g, e, a] has 12 sorted combinations
    [g, e, c] has 28 sorted combinations
    [g, e, b] has 4 sorted combinations
    [g, e, d] has 20 sorted combinations
    [g, e, f] has 0 sorted combinations
    [g, d, a] has 6 sorted combinations
    [g, d, c] has 12 sorted combinations
    [g, d, b] has 1 sorted combinations
    [g, d, e] has 4 sorted combinations
    [g, d, f] has 0 sorted combinations
    [g, f, a] has 2 sorted combinations
    [g, f, c] has 5 sorted combinations
    [g, f, b] has 1 sorted combinations
    [g, f, e] has 6 sorted combinations
    [g, f, d] has 4 sorted combinations
    [f, a, c] has 2 sorted combinations
    [f, a, b] has 0 sorted combinations
    [f, a, e] has 0 sorted combinations
    [f, a, d] has 2 sorted combinations
    [f, a, g] has 0 sorted combinations
    [f, c, a] has 8 sorted combinations
    [f, c, b] has 0 sorted combinations
    [f, c, e] has 2 sorted combinations
    [f, c, d] has 8 sorted combinations
    [f, c, g] has 0 sorted combinations
    [f, b, a] has 2 sorted combinations
    [f, b, c] has 5 sorted combinations
    [f, b, e] has 2 sorted combinations
    [f, b, d] has 3 sorted combinations
    [f, b, g] has 0 sorted combinations
    [f, e, a] has 12 sorted combinations
    [f, e, c] has 28 sorted combinations
    [f, e, b] has 4 sorted combinations
    [f, e, d] has 20 sorted combinations
    [f, e, g] has 0 sorted combinations
    [f, d, a] has 6 sorted combinations
    [f, d, c] has 12 sorted combinations
    [f, d, b] has 1 sorted combinations
    [f, d, e] has 4 sorted combinations
    [f, d, g] has 0 sorted combinations
    [f, g, a] has 0 sorted combinations
    [f, g, c] has 0 sorted combinations
    [f, g, b] has 0 sorted combinations
    [f, g, e] has 0 sorted combinations
    [f, g, d] has 0 sorted combinations
    

    【讨论】:

      【解决方案3】:

      您可以通过一种巧妙的方式执行此操作 - 对于每个现有列表,将其中的每个数字映射到下一个大于它的数字列表中的计数。一旦你有了这些计数,明智的产品总和应该会让你得到你需要的计数。

      这是一个如何获得计数的示例:

      D = {'x': [15, 20],
           'y': [11, 12, 14, 16, 19],
           'z': [7, 9, 17, 18]}
      
      order = ['x', 'y', 'z']
      pairs = zip(order[:-1], order[1:])
      
      counts = dict()
      for pair in pairs:
          counts[pair[0]] = dict()
          for num in D[pair[0]]:
              counts[pair[0]][num] = len([el for el in D[pair[1]] if el >= num])
      

      EDIT 在 OP 对问题进行编辑之后,以获得更清晰的问题:

      您需要为这个问题构建一个动态编程解决方案(我假设您对DP algorithms 有一定的背景;如果没有,请看一些)。假设您的原始字典有 n 键。然后你需要三个长度为n 的字典,例如M1M2M3。对于每个键和数字,M3[key][number] 将存储 number 可以成为元组的第三个元素的方式数(这将是相同的 1)。 M2[key][number] 将是 number 可以成为元组的第二个元素的方式数(这必须从 M3 向后动态构造),M1[key][number] 将是 number 可以的方式数成为元组的第一个元素。 M1 必须从 M2 构造。您的最终解决方案将是 M1 中元素的总和。 M1M2M3的更新规则和初始化留给大家。

      例如,要填写M1[key][number] 中的条目,假设downkeyskey 之后的一组键。对于每个downkey,您将查看M2[downkey] 的条目并将M2[downkey][num2] 的值相加,其中num2 大于number。为所有downkeys 添加所有此类数字将为您提供M1[key][number] 的条目。因此,这会提示您更新M1M2 的行的顺序。

      如果您认为这是一项繁重的工作 - 嗯,确实如此,但它仍然是多项式,而不是像笛卡尔积那样的指数。即使是笛卡尔乘积方式 - 您必须首先找到 n 列表中的 3 个的所有可能组合,然后获取乘积,然后过滤它们。这非常昂贵。动态规划解决方案重用每一步的信息,而不是每次都重新计算。

      【讨论】:

      • 你能用一些代码来说明这一点吗?我没有看到这如何避免任何额外的计算。这不是本质上相同的笛卡尔积吗?从 {15: 2, 20: 0}, {11: 2, 12: 2, 14: 2, 16: 2, 19: 0} 我如何明智地总结这些? (编辑:我看到你添加了一些代码,但我仍然没有完全关注)
      • 我现在必须出去,所以我无法完成代码,但这比生成所有笛卡尔积的计算量要小得多。这与动态编程解决方案所节省的成本相同(基本上这就是您计算“明智”总和的方式)。
      • 谢谢。如果您有机会能说明我如何从计数字典中得出正确答案 2,我将不胜感激!
      • 您的第一个问题说您想从每个列表中获取一个元素,但在您的第二个示例中,您只从原始 7 中的 3 个中获取。我为您想要一个的情况编写了代码从每个列表中,我认为它有效,但这不是你想要做的。那么你的问题有点困难,但仍然可以有效地完成。我现在不能为你编写代码,但我会编辑我的答案给你一个路线图。
      • 我应该提到的是,当我一次拿 3 个钥匙时,我也只是按排序顺序拿它们。因此,在我的第二个示例中,第一个有效答案包含来自“b”、“d”和“e”列表的元素。我永远不会以不同的顺序看待它们。所以,我问“有多少种方法可以从与一组排序的 3 个键相关联的每个列表中选择一个项目,以便对这些项目进行排序?”这是一口。
      猜你喜欢
      • 2021-10-22
      • 2019-07-23
      • 2012-08-17
      • 2012-03-24
      • 2015-12-05
      • 1970-01-01
      • 2012-05-18
      • 1970-01-01
      • 2017-07-15
      相关资源
      最近更新 更多