【问题标题】:Permutations of a list with 16 integers but only if 4 conditions are fulfilled具有 16 个整数的列表的排列,但前提是满足 4 个条件
【发布时间】:2019-12-25 17:53:56
【问题描述】:

我有一个整数列表

keys = [18, 99, 86, 61, 66, 81, 98, 19, 91, 16, 69, 88, 89, 68, 11, 96]

我想找到 this 列表的所有排列,这样对于每个排列

  1. 元素 0 到 3 加起来为 264,

  2. 元素 4 到 7 加起来是 264,

  3. 元素 8 到 11 加起来是 264 和

  4. 元素 12 到 15 到 264。

目前我有以下策略

  1. 使用 itertools.permutations 计算所有排列

  2. 检查哪些排列满足我的条件

还有其他性能更好的策略吗?

【问题讨论】:

  • 我意识到我的问题可以用更好的方式提出。我进行了更新。 @ChrisDoyle
  • 请不要关闭这个,我正在研究解决方案。
  • 在我看来,计算所有排列然后检查满足 s 的排列与生成单个排列并检查它是否符合标准的速度大致相同。然后生成下一个。您仍然需要进行 N 次排列 a dn N 次计算
  • 能否请您评论一下为什么您认为该问题集中在多个问题上? @jonrsharpe
  • 试试这个,太棒了,在它关闭之前,我距离添加这个答案只有两秒钟的时间。它真的很酷,想分享它,你只需要 pip install more_itertools: from more_itertools import distinct_combinations import numpy as np np.array(list(distinct_combinations(keys,4)))[[sum(x)==264 for x在 distinct_combinations(keys,4)]]

标签: python combinations permutation constraint-satisfaction


【解决方案1】:

好的,这里是如何做的初步想法。它生成所有总和为 264 的 4x4 子集集的组合(只有 675 个这样的有序组合)。

接下来,您需要对 25 种组合中的每一种中的 4 组进行排列。这应该会产生大约 2.24 亿个解决方案。这种方式比你的蛮力生成和检查快大约 90 000 倍。

from itertools import combinations

keys = [18, 99, 86, 61, 66, 81, 98, 19, 91, 16, 69, 88, 89, 68, 11, 96]
keys_set = set(keys)

def f(key_set):

    for i in combinations(keys_set,4):
        if sum(i) == 264:
            rem_set = keys_set - set(i)
            for j in combinations(rem_set,4):
                if sum(j) == 264:
                    rem_set2 = rem_set - set(j)
                    for k in combinations(rem_set2,4):
                        if sum(k) == 264:
                            rem_set3 = rem_set2 - set(k)
                            if sum(rem_set3) == 264:
                                yield i,k,j,rem_set3

for i,k,j,l in f(keys_set):
     for a in product(permutations(i), permutations(j), permutations(k), permutations(l)):
        print(a)

我为丑陋的代码道歉,但我认为在问题结束之前找到解决方案很重要。下面是一个更简洁的版本。

def g(key_set):
    for i in combinations(key_set,4):
        if sum(i) == 264:
            yield i, key_set- set(i)

def g2(key_set):
    for i, r in g(key_set):
        for j, r2 in g(r):
            for k, r3 in g(r2):
                for l, r in g(r3):
                    yield i,j,k,l



for i,j,k,l in g2(keys_set):
    for a in product(permutations(i), permutations(j), permutations(k), permutations(l)):
        print(a)

【讨论】:

  • 此代码的第一次打印产生 (96, 66, 11, 91), (99, 18, 86, 61), (99, 18, 86, 61), {88, 89, 19 , 68}),其中 (99, 18, 86, 61) 出现两次,这是无效的。由于 99 在列表中只出现一次
  • 那里的产量小错误,产生 i,k,k 而不是 i,k,j
  • 注意:如果你有重复的键,这会很糟糕
  • 嗯,我提供的初始列表 keys = [18, 99, 86, 61, 66, 81, 98, 19, 91, 16, 69, 88, 89, 68, 11, 96 ] 未列在您的印刷品中,但它满足条件
  • 添加了如何获取完整列表(虽然很长)
【解决方案2】:

您可以将递归与生成器一起使用:

keys = [18, 99, 86, 61, 66, 81, 98, 19, 91, 16, 69, 88, 89, 68, 11, 96]
req = {(0, 3): 264, (4, 7): 264, (8, 11): 264, (12, 15): 264}
def combos(d, c = []):
  if len(d) == len(c):
     yield c
  else:
     for i in filter(lambda x:x not in c, d):
        if all(sum(_k[a:b+1]) == j if len((_k:=(c+[i]))) == b+1 else sum(_k[a:b+1]) <= j for (a, b), j in req.items()):
          yield from combos(d, _k)


l = combos(keys)

由于可能的组合数量众多,如果您尝试将所有生成器值加载到列表中,即list(combos(keys)),此解决方案将挂起。但是,您可以迭代 l 所需的次数以访问生成的结果:

for _ in range(100):
   print(next(l, None))

输出:

 [18, 99, 86, 61, 66, 81, 98, 19, 91, 16, 69, 88, 89, 68, 11, 96]
 [18, 99, 86, 61, 66, 81, 98, 19, 91, 16, 69, 88, 89, 68, 96, 11]
 [18, 99, 86, 61, 66, 81, 98, 19, 91, 16, 69, 88, 89, 11, 68, 96]
 [18, 99, 86, 61, 66, 81, 98, 19, 91, 16, 69, 88, 89, 11, 96, 68]
 [18, 99, 86, 61, 66, 81, 98, 19, 91, 16, 69, 88, 89, 96, 68, 11]
 [18, 99, 86, 61, 66, 81, 98, 19, 91, 16, 69, 88, 89, 96, 11, 68]
 [18, 99, 86, 61, 66, 81, 98, 19, 91, 16, 69, 88, 68, 89, 11, 96]
 ...

【讨论】:

    【解决方案3】:

    这些数字有 672 个符合条件的唯一组合。我没有在独特的组合中进行置换,因为我认为这是我没有的计算周期练习:-)。这些是等于 264 的 4x4 数字的 672 个独特组合。如果你想在这些独特组合中置换,数字会大大增加,但我认为重要的部分是展示完成任务可能的独特组合。

    keys = np.array([18, 99, 86, 61, 66, 81, 98, 19, 91, 16, 69, 88, 89, 68, 11, 96])
    
    import itertools
    unique_data = np.array(list(itertools.combinations(keys,4)))[[sum(x)==264 for x in itertools.combinations(keys,4)]]
    
    i=0 
    for w in unique_data: 
     for x in unique_data: 
      for y in unique_data: 
        for z in unique_data:    
          if len(set(x)|set(y)|set(w)|set(z))==16: 
            print(x,y,w,z) 
            i+=1 
    

    输出:

    [66 81 98 19] [91 16 69 88] [18 99 86 61] [89 68 11 96]
    [66 81 98 19] [91 16 89 68] [18 99 86 61] [69 88 11 96]
    [66 81 98 19] [69 88 11 96] [18 99 86 61] [91 16 89 68]
    [66 81 98 19] [89 68 11 96] [18 99 86 61] [91 16 69 88]
    [66 98 89 11] [81 19 68 96] [18 99 86 61] [91 16 69 88]
    [66 98 89 11] [91 16 69 88] [18 99 86 61] [81 19 68 96]
    [66 19 91 88] [81 98 16 69] [18 99 86 61] [89 68 11 96]
    [66 19 91 88] [89 68 11 96] [18 99 86 61] [81 98 16 69]
    [66 91 11 96] [81 98 16 69] [18 99 86 61] [19 88 89 68]
    [66 91 11 96] [19 88 89 68] [18 99 86 61] [81 98 16 69]
    [81 98 16 69] [66 19 91 88] [18 99 86 61] [89 68 11 96]
    [81 98 16 69] [66 91 11 96] [18 99 86 61] [19 88 89 68]
    [81 98 16 69] [19 88 89 68] [18 99 86 61] [66 91 11 96]
    [81 98 16 69] [89 68 11 96] [18 99 86 61] [66 19 91 88]
    [81 19 68 96] [66 98 89 11] [18 99 86 61] [91 16 69 88]
    [81 19 68 96] [91 16 69 88] [18 99 86 61] [66 98 89 11]
    [19 88 89 68] [66 91 11 96] [18 99 86 61] [81 98 16 69]
    [19 88 89 68] [81 98 16 69] [18 99 86 61] [66 91 11 96]
    [91 16 69 88] [66 81 98 19] [18 99 86 61] [89 68 11 96]
    [91 16 69 88] [66 98 89 11] [18 99 86 61] [81 19 68 96]
    [91 16 69 88] [81 19 68 96] [18 99 86 61] [66 98 89 11]
    [91 16 69 88] [89 68 11 96] [18 99 86 61] [66 81 98 19]
    [91 16 89 68] [66 81 98 19] [18 99 86 61] [69 88 11 96]
    [91 16 89 68] [69 88 11 96] [18 99 86 61] [66 81 98 19]
    [69 88 11 96] [66 81 98 19] [18 99 86 61] [91 16 89 68]
    [69 88 11 96] [91 16 89 68] [18 99 86 61] [66 81 98 19]
    [89 68 11 96] [66 81 98 19] [18 99 86 61] [91 16 69 88]
    [89 68 11 96] [66 19 91 88] [18 99 86 61] [81 98 16 69]
    [89 68 11 96] [81 98 16 69] [18 99 86 61] [66 19 91 88]
    [89 68 11 96] [91 16 69 88] [18 99 86 61] [66 81 98 19]
    [86 61 98 19] [91 16 69 88] [18 99 66 81] [89 68 11 96]
    [86 61 98 19] [91 16 89 68] [18 99 66 81] [69 88 11 96]
    [86 61 98 19] [69 88 11 96] [18 99 66 81] [91 16 89 68]
    [86 61 98 19] [89 68 11 96] [18 99 66 81] [91 16 69 88]
    [86 98 69 11] [61 19 88 96] [18 99 66 81] [91 16 89 68]
    [86 98 69 11] [61 91 16 96] [18 99 66 81] [19 88 89 68]
    [86 98 69 11] [19 88 89 68] [18 99 66 81] [61 91 16 96]
    [86 98 69 11] [91 16 89 68] [18 99 66 81] [61 19 88 96]
    [86 19 91 68] [61 98 16 89] [18 99 66 81] [69 88 11 96]
    [86 19 91 68] [69 88 11 96] [18 99 66 81] [61 98 16 89]
    [61 98 16 89] [86 19 91 68] [18 99 66 81] [69 88 11 96]
    [61 98 16 89] [69 88 11 96] [18 99 66 81] [86 19 91 68]
    [61 19 88 96] [86 98 69 11] [18 99 66 81] [91 16 89 68]
    [61 19 88 96] [91 16 89 68] [18 99 66 81] [86 98 69 11]
    [61 91 16 96] [86 98 69 11] [18 99 66 81] [19 88 89 68]
    [61 91 16 96] [19 88 89 68] [18 99 66 81] [86 98 69 11]
    [19 88 89 68] [86 98 69 11] [18 99 66 81] [61 91 16 96]
    [19 88 89 68] [61 91 16 96] [18 99 66 81] [86 98 69 11]
    [91 16 69 88] [86 61 98 19] [18 99 66 81] [89 68 11 96]
    [91 16 69 88] [89 68 11 96] [18 99 66 81] [86 61 98 19]
    [91 16 89 68] [86 61 98 19] [18 99 66 81] [69 88 11 96]
    [91 16 89 68] [86 98 69 11] [18 99 66 81] [61 19 88 96]
    [91 16 89 68] [61 19 88 96] [18 99 66 81] [86 98 69 11]
    [91 16 89 68] [69 88 11 96] [18 99 66 81] [86 61 98 19]
    [69 88 11 96] [86 61 98 19] [18 99 66 81] [91 16 89 68]
    [69 88 11 96] [86 19 91 68] [18 99 66 81] [61 98 16 89]
    [69 88 11 96] [61 98 16 89] [18 99 66 81] [86 19 91 68]
    [69 88 11 96] [91 16 89 68] [18 99 66 81] [86 61 98 19]
    [89 68 11 96] [86 61 98 19] [18 99 66 81] [91 16 69 88]
    [89 68 11 96] [91 16 69 88] [18 99 66 81] [86 61 98 19]
    [99 61 16 88] [66 81 98 19] [18 86 91 69] [89 68 11 96]
    [99 61 16 88] [66 98 89 11] [18 86 91 69] [81 19 68 96]
    ...
    

    【讨论】:

      【解决方案4】:

      这应该会快一点,因为我限制了我们从中获得组合的元素数量(我只调用了一次组合)。这也利用了keys 的独特性:

      import itertools
      import numpy as np
      def foo():
          keys = [18, 99, 86, 61, 66, 81, 98, 19, 91, 16, 69, 88, 89, 68, 11, 96]
          n=4
          s=264
          lst=[el for el in itertools.combinations(keys, n) if sum(el)==s]
          for el in itertools.product(lst,repeat=4):
              if len(set(np.array(el).ravel()))==16:
                  yield np.array(el).ravel()
      
      for el in foo():
          print(el)
      

      输出:

      [18 99 86 61 66 81 98 19 91 16 69 88 89 68 11 96]
      [18 99 86 61 66 81 98 19 91 16 89 68 69 88 11 96]
      [18 99 86 61 66 81 98 19 69 88 11 96 91 16 89 68]
      [18 99 86 61 66 81 98 19 89 68 11 96 91 16 69 88]
      [18 99 86 61 66 98 89 11 81 19 68 96 91 16 69 88]
      [18 99 86 61 66 98 89 11 91 16 69 88 81 19 68 96]
      [18 99 86 61 66 19 91 88 81 98 16 69 89 68 11 96]
      [18 99 86 61 66 19 91 88 89 68 11 96 81 98 16 69]
      ...
      

      (如果您希望将结果保留为四个四元素元组的格式,您可以删除行中的.ravel(),其中我是yield

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-08-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-07-14
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多