In Python; what is the best way to get a list of combinations for k groups of n members and l groups of m members given a list of possible members g?
Example, given a list of elements:
g = ["A", "B", "C", "D", "E", "F", "G"]
What I want is to have a list li of all combinations for e.g. 2(=k) groups of 2(=n) and 1(=l) group of 3(=m):
[["AB", "CD", "EFG"],
["AC", "BD", "EFG"],
["AD", "CB", "EFG"],
["AE", "CD", "BFG"],
["AF", "CD", "BEG"],... ]
I don't want any repetition of elements accross any of the groups (equivalent of saying: I want every different element to appear once accross all the groups for every different combination).
E.g.
["AB", "AD", "EFG"]is not a valid combination as it has the elementAmore than once accross all groups.
I don't want different permutations inside a group;
E.g.
["AB", "CD", "EFG"]should not be repeated in a form like["BA", "DC", "EGF"].
Also, if a combination appears in any of the k-groups I don't want that same combination in the k-groups if the l-groups are just the same (and same for l-groups).
E.g. if
["AB", "CD", "EFG"]appears,[ "CD", "AB", "EFG"]should not appear again.
To be clear, I'm only interested in the case where the groups will always fit neatly/exactly in the total group of elements to be used(g):
E.g.
2x2 + 1x3 == 7 == len(["A", "B", "C", "D", "E", "F", "G"]),1x2 + 1x3 == 5 == len(["A", "B", "C", "D", "E"]).
I could use Python's permutations function and just group together in k groups of n and l groups of m in each permutation, but I will have a lot of unnecessary iterations for more elements.
EDIT: Code edited to meet updated requirement (rule 3).
Code:
import itertools as it
def unique_group(iterable, k, n):
"""Return an iterator, comprising groups of size `k` with combinations of size `n`."""
# Build separate combinations of `n` characters
groups = ("".join(i) for i in it.combinations(iterable, n)) # 'AB', 'AC', 'AD', ...
# Build unique groups of `k` by keeping the longest sets of characters
return (i for i in it.combinations(groups, k)
if len(set("".join(i))) == sum((map(len, i)))) # ('AB', 'CD'), ('AB', 'CE'), ...
def combined(groups1, groups2):
"""Return an iterator with unique combinations of groups (k and l)."""
# Build a unique cartesian product of groups `k` and `l`, filtering non-disjoints
return (i[0] + i[1]
for i in it.product(groups1, groups2)
if set("".join(i[0])).isdisjoint(set("".join(i[-1]))))
iterable = "ABCDEFG"
g1 = unique_group(iterable, 2, 2)
g2 = unique_group(iterable, 1, 3)
result = list(combined(g1, g2))
print(len(result))
result
Output:
105
[('AB', 'CD', 'EFG'),
('AB', 'CE', 'DFG'),
...,
('BC', 'AD', 'EFG'),
('BC', 'AE', 'DFG'),
...,
]
Details and insight can be found in a demonstration.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With