首页 > 解决方案 > 如何获得给定数量的图层变体的独特组合,同时使用 Python 保持每个图层变体的给定比例?

问题描述

我需要用 Python 编写一个脚本来解决这个任务,但我不知道该怎么做。

我有物品(让我们将它们命名为图层):A、B、C...

每层可以有任意数量的变化。

对于每个变化,给出我们想要在输出中获得的百分比百分比。

在输出端,我们必须根据给定的比例获得所有层的给定数量的唯一组合。

例如:

layers = [
   {'A0':'30%', 'A1':'30%', 'A2':'40%'},
   {'B0':'10%', 'B1': '20%', 'B2' '40%', 'B3':'30%'},
   {'C0':'50%'}
]

如果我想获得 A、B、C 层变化的 10 种独特组合,脚本应该像这样输出数据集:

[
    ('A0', 'B0'), 
    ('A0', 'B1', 'C0'), 
    ('A0', 'B1'), 
    ('A1', 'B2', 'C0'), 
    ('A1', 'B2'), 
    ('A1', 'B3', 'C0'), 
    ('A2', 'B2', 'C0'), 
    ('A2', 'B2'), 
    ('A2', 'B3', 'C0'), 
    ('A2', 'B3')
]

因此,每一层变化的计数应该与给定的比例一致:

A0 = 3, A1 = 3, A2 = 4
B0 = 1, B1 = 2, B2 = 4, B3 = 3,
C0 = 5

如果我们想要获得 20 种变化,那么计数会有所不同:

A0 = 6, A1 = 6, A2 = 8
B0 = 2, B1 = 4, B2 = 8, B3 = 6,
C0 = 10

它应该适用于任意数量的层、变化、比例并获得输出组合的准确计数(或组合的最大值,如果没有更多组合来获得准确的数量)

标签: pythonnumpycombinationscombinatoricscartesian-product

解决方案


对于每一层,您都可以找到分布列表,然后递归地合并结果以产生组合。由于 可能导致的组合数量非常多,get_combos后者是一个生成器,您可以使用它next来按需生成值:

import itertools
layers = [{'A0': '30%', 'A1': '30%', 'A2': '40%'}, {'B0': '10%', 'B1': '20%', 'B2': '40%', 'B3': '30%'}, {'C0': '50%'}]
def layer_combos(l, d):
  return [i for a, b in l.items() for i in ([a]*int((d*(int(b[:-1])/float(100)))))]

def get_offsets(l, d, c = []):
   if not d:
      yield tuple(c)
   else:
      if l:
         yield from get_offsets(l[1:], d-1, c+[l[0]])
      if not c or c[-1] is not None:
         for i in range(d - len(l)):
             yield from get_offsets(l, d-(i+1), c+([None]*(i+1)))

def get_combos(l, d, c = []):
  if not l:
     if len((l:=[tuple(list(filter(None, i))) for i in zip(*c)])) == len(set(l)):
        yield l
  else:
     for i in itertools.permutations((l1:=layer_combos(l[0], d)), (l2:=len(l1))):
        for j in set(get_offsets(i, d)):
           yield from get_combos(l[1:], d, c + [j])
           

result = get_combos(layers, 10)
for _ in range(10): #first ten combinations
  print(next(result))

输出:

[('A0', 'B0', 'C0'), ('A0', 'B1', 'C0'), ('A0', 'B1'), ('A1', 'B2', 'C0'), ('A1', 'B2'), ('A1', 'B3'), ('A2', 'B2'), ('A2', 'B2', 'C0'), ('A2', 'B3', 'C0'), ('A2', 'B3')]
[('A0', 'B0', 'C0'), ('A0', 'B1', 'C0'), ('A0', 'B1'), ('A1', 'B2', 'C0'), ('A1', 'B2'), ('A1', 'B3'), ('A2', 'B2'), ('A2', 'B2', 'C0'), ('A2', 'B3'), ('A2', 'B3', 'C0')]
[('A0', 'B0', 'C0'), ('A0', 'B1', 'C0'), ('A0', 'B1'), ('A1', 'B2'), ('A1', 'B2', 'C0'), ('A1', 'B3'), ('A2', 'B2', 'C0'), ('A2', 'B2'), ('A2', 'B3', 'C0'), ('A2', 'B3')]
[('A0', 'B0'), ('A0', 'B1', 'C0'), ('A0', 'B1'), ('A1', 'B2'), ('A1', 'B2', 'C0'), ('A1', 'B3', 'C0'), ('A2', 'B2'), ('A2', 'B2', 'C0'), ('A2', 'B3'), ('A2', 'B3', 'C0')]
[('A0', 'B0'), ('A0', 'B1'), ('A0', 'B1', 'C0'), ('A1', 'B2'), ('A1', 'B2', 'C0'), ('A1', 'B3', 'C0'), ('A2', 'B2', 'C0'), ('A2', 'B2'), ('A2', 'B3'), ('A2', 'B3', 'C0')]
[('A0', 'B0', 'C0'), ('A0', 'B1'), ('A0', 'B1', 'C0'), ('A1', 'B2'), ('A1', 'B2', 'C0'), ('A1', 'B3'), ('A2', 'B2', 'C0'), ('A2', 'B2'), ('A2', 'B3', 'C0'), ('A2', 'B3')]
[('A0', 'B0', 'C0'), ('A0', 'B1', 'C0'), ('A0', 'B1'), ('A1', 'B2', 'C0'), ('A1', 'B2'), ('A1', 'B3'), ('A2', 'B2', 'C0'), ('A2', 'B2'), ('A2', 'B3', 'C0'), ('A2', 'B3')]
[('A0', 'B0', 'C0'), ('A0', 'B1'), ('A0', 'B1', 'C0'), ('A1', 'B2', 'C0'), ('A1', 'B2'), ('A1', 'B3'), ('A2', 'B2', 'C0'), ('A2', 'B2'), ('A2', 'B3'), ('A2', 'B3', 'C0')]
[('A0', 'B0'), ('A0', 'B1', 'C0'), ('A0', 'B1'), ('A1', 'B2', 'C0'), ('A1', 'B2'), ('A1', 'B3', 'C0'), ('A2', 'B2', 'C0'), ('A2', 'B2'), ('A2', 'B3', 'C0'), ('A2', 'B3')]
[('A0', 'B0'), ('A0', 'B1', 'C0'), ('A0', 'B1'), ('A1', 'B2', 'C0'), ('A1', 'B2'), ('A1', 'B3', 'C0'), ('A2', 'B2'), ('A2', 'B2', 'C0'), ('A2', 'B3', 'C0'), ('A2', 'B3')]

推荐阅读