Here is the combination / permutator generator function that uses any number of lists with values and any length of template strings. The generator creates corresponding lists with combinations / permutations of values matching the template string. The answer was given by a colleague here: https://stackoverflow.com/a/48121777/8820330
from itertools import permutations, combinations, product
def groups(sources, template, mode='P'):
func = permutations if mode == 'P' else combinations
keys = sources.keys()
combos = [func(sources[k], template.count(k)) for k in keys]
for t in product(*combos):
d = {k: iter(v) for k, v in zip(keys, t)}
yield [next(d[k]) for k in template]
# tests
sources = {
'a': [0, 1, 2],
'b': [3, 4, 5],
'c': [6, 7, 8],
}
templates = 'aa', 'abc', 'abba', 'cab'
for template in templates:
print('\ntemplate', template)
for i, t in enumerate(groups(sources, template, mode='C'), 1):
print(i, t)
Output:
template aa
1 [0, 1]
2 [0, 2]
3 [1, 2]
template abc
1 [0, 3, 6]
2 [0, 3, 7]
3 [0, 3, 8]
4 [0, 4, 6]
5 [0, 4, 7]
6 [0, 4, 8]
7 [0, 5, 6]
8 [0, 5, 7]
9 [0, 5, 8]
10 [1, 3, 6]
11 [1, 3, 7]
12 [1, 3, 8]
13 [1, 4, 6]
14 [1, 4, 7]
15 [1, 4, 8]
16 [1, 5, 6]
17 [1, 5, 7]
18 [1, 5, 8]
19 [2, 3, 6]
20 [2, 3, 7]
21 [2, 3, 8]
22 [2, 4, 6]
23 [2, 4, 7]
24 [2, 4, 8]
25 [2, 5, 6]
26 [2, 5, 7]
27 [2, 5, 8]
template abba
1 [0, 3, 4, 1]
2 [0, 3, 5, 1]
3 [0, 4, 5, 1]
4 [0, 3, 4, 2]
5 [0, 3, 5, 2]
6 [0, 4, 5, 2]
7 [1, 3, 4, 2]
8 [1, 3, 5, 2]
9 [1, 4, 5, 2]
template cab
1 [6, 0, 3]
2 [7, 0, 3]
3 [8, 0, 3]
4 [6, 0, 4]
5 [7, 0, 4]
6 [8, 0, 4]
7 [6, 0, 5]
8 [7, 0, 5]
9 [8, 0, 5]
10 [6, 1, 3]
11 [7, 1, 3]
12 [8, 1, 3]
13 [6, 1, 4]
14 [7, 1, 4]
15 [8, 1, 4]
16 [6, 1, 5]
17 [7, 1, 5]
18 [8, 1, 5]
19 [6, 2, 3]
20 [7, 2, 3]
21 [8, 2, 3]
22 [6, 2, 4]
23 [7, 2, 4]
24 [8, 2, 4]
25 [6, 2, 5]
26 [7, 2, 5]
27 [8, 2, 5]
As you can see, the generator supports strings of templates built of single characters. However, I am interested in how to transform the above generator, to support the templates' strings, for example in this form:
sources = {
'a1' = [0,1,2],
'a2' = [3,4,5],
'a3' = [6,7,8],
}
templates = 'a1a2a3'
It seems to me that the problem lies in the iteration of the string from templates
, where the iteration runs after the individual elements. In my case, however, iteration would have to follow pairs from a given string. How can this be done?
Define your templates like this:
And then it will work out of the box. The reason this works is that strings in python are in fact just lists of characters, so instead of defining 'abc' you could define ['a', 'b', 'c'] and this behaves the same in most situations.