簡體   English   中英

在 Python 中生成滿足多個條件的排列?

[英]Generating permutations that meet multiple criteria in Python?

我正在嘗試生成滿足各種子標准的所有可能排列的列表。 我不能采取蠻力方法,因為 memory 的使用將是一個問題。 理想情況下,我會使用 itertools 和生成器的某種組合來管理生成的排列的數量。

客觀的

生成 20 個項目的排列,這些排列分為 5 個項目的四個子集。

約束

  1. 每個項目可以等於 4、5 或 6
  2. 每個排列集的總和必須總計 100
  3. 每個子集的總和必須在 20 到 30 之間

例子

66655 / 44455 / 46465 / 56644 是允許的,因為子組件總和在 20 到 30 (28 / 22 / 25 / 25) 之間,並且總和等於 100。

不幸的是,我真的不知道從哪里開始。 任何指導將不勝感激。

這將產生數億個有效的解決方案。 將它們存儲在列表中需要 3GB 的 memory,但您可以在不存儲它們的情況下生成解決方案。

以下是你如何生產它們(我只是在這個例子中計算它們):

在子集總數 (20,21,22,...30) 和可以產生它們的數字 4,5,6 的排列之間創建映射

from itertools import permutations,product,chain

subSums = dict()
for combo in combinations([4,5,6]*5,5):
    if sum(combo) not in range(20,31): continue
    subSums.setdefault(sum(combo),set()).add(combo)
            
print(sum(map(len,subSums.values()))) # 243
for subtotal,combos in sorted(subSums.items()):
    print(subtotal,len(combos),":",[*combos][:3],"..."*(len(combos)>3))

20 1 : [(4, 4, 4, 4, 4)] 
21 5 : [(4, 5, 4, 4, 4), (5, 4, 4, 4, 4), (4, 4, 5, 4, 4)] ...
22 15 : [(4, 5, 4, 5, 4), (4, 4, 4, 6, 4), (4, 4, 5, 5, 4)] ...
23 30 : [(4, 4, 5, 6, 4), (4, 4, 6, 5, 4), (6, 5, 4, 4, 4)] ...
24 45 : [(5, 4, 6, 4, 5), (5, 4, 4, 6, 5), (5, 5, 4, 4, 6)] ...
25 51 : [(6, 4, 5, 6, 4), (6, 4, 6, 5, 4), (6, 5, 5, 5, 4)] ...
26 45 : [(5, 5, 5, 5, 6), (5, 4, 5, 6, 6), (5, 4, 6, 5, 6)] ...
27 30 : [(6, 5, 6, 5, 5), (6, 5, 5, 6, 5), (6, 6, 5, 6, 4)] ...
28 15 : [(4, 6, 6, 6, 6), (5, 5, 6, 6, 6), (6, 6, 4, 6, 6)] ...
29 5 : [(5, 6, 6, 6, 6), (6, 6, 6, 6, 5), (6, 5, 6, 6, 6)] ...
30 1 : [(6, 6, 6, 6, 6)] 

生成 20,21,22,...30 中 4 個小計的排列,加起來為 100

groupSums = set()
for combo in combinations([*range(20,31)]*4,4):
    if sum(combo) != 100: continue
    groupSums.add(combo)
    
print(len(groupSums)) # 891
for group in sorted(groupSums): print(group)

(20, 20, 30, 30)
(20, 21, 29, 30)
(20, 21, 30, 29)
(20, 22, 28, 30)
(20, 22, 29, 29)
(20, 22, 30, 28)
(20, 23, 27, 30)
(20, 23, 28, 29)
(20, 23, 29, 28)
(20, 23, 30, 27)
...

對於 4 個小計的每個排列,結合可以產生每個小計的 4、5、6 的排列

solutions      = [] # not going to actually fill this
totalSolutions = 0
for g1,g2,g3,g4 in groupSums:
    groupSolutions  = len(subSums[g1])
    groupSolutions *= len(subSums[g2])
    groupSolutions *= len(subSums[g3])
    groupSolutions *= len(subSums[g4])
    totalSolutions += groupSolutions

    # actual solutions would be
    # for solution in product(subSums[g1],subSums[g2],subSums[g3],subSums[g4]):
    #     solutions.append([*chain.from_iterable(solution)])
    
print(totalSolutions) # 377,379,369 solutions

如果您只需要生成解決方案(而不是將它們存儲在列表中),您可以制作一個生成器 function:

def genGroups():
    for g1,g2,g3,g4 in groupSums:
        yield from product(subSums[g1],subSums[g2],subSums[g3],subSums[g4])

for solution in genGroups(): 
    g1,g2,g3,g4 = map(sum,solution)
    print((g1,g2,g3,g4),":",*chain.from_iterable(solution))

(20, 30, 27, 23) : 4 4 4 4 4 6 6 6 6 6 6 5 6 5 5 4 4 5 6 4
(20, 30, 27, 23) : 4 4 4 4 4 6 6 6 6 6 6 5 6 5 5 4 4 6 5 4
(20, 30, 27, 23) : 4 4 4 4 4 6 6 6 6 6 6 5 6 5 5 6 5 4 4 4
(20, 30, 27, 23) : 4 4 4 4 4 6 6 6 6 6 6 5 6 5 5 5 6 4 4 4
(20, 30, 27, 23) : 4 4 4 4 4 6 6 6 6 6 6 5 6 5 5 5 5 4 5 4
...
(29, 21, 26, 24) : 5 6 6 6 6 5 4 4 4 4 6 6 5 4 5 4 5 4 5 6
(29, 21, 26, 24) : 5 6 6 6 6 5 4 4 4 4 6 6 5 4 5 4 5 5 4 6
(29, 21, 26, 24) : 5 6 6 6 6 5 4 4 4 4 6 6 5 4 5 4 6 5 5 4
(29, 21, 26, 24) : 5 6 6 6 6 5 4 4 4 4 6 6 5 4 5 4 5 6 4 5
(29, 21, 26, 24) : 5 6 6 6 6 5 4 4 4 4 6 6 5 4 5 4 5 4 6 5
...
(22, 28, 22, 28) : 5 4 5 4 4 6 5 6 5 6 5 4 5 4 4 6 6 6 5 5
(22, 28, 22, 28) : 5 4 5 4 4 6 5 6 5 6 5 4 5 4 4 6 5 6 6 5
(22, 28, 22, 28) : 5 4 5 4 4 6 5 6 5 6 5 4 5 4 4 5 6 6 5 6
(22, 28, 22, 28) : 5 4 5 4 4 6 5 6 5 6 5 4 5 4 4 5 6 5 6 6
(22, 28, 22, 28) : 5 4 5 4 4 6 5 6 5 6 5 4 5 4 4 6 6 6 6 4
(22, 28, 22, 28) : 5 4 5 4 4 6 5 6 5 6 5 4 5 4 4 6 5 6 5 6

在我的筆記本電腦上生成所有解決方案而不存儲它們需要 27 秒。

sum(1 for _ in genGroups()) # 377379369 in 27.49 seconds

生成器可用於填充列表(而不是上面的 for 循環):

L = list(genGroups())

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM