Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get list of combinations for K groups of N members and L groups of M members

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"],... ]
  1. 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 element A more than once accross all groups.

  2. 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"].

  3. 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.

like image 469
Bentley4 Avatar asked Nov 01 '25 01:11

Bentley4


1 Answers

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.

like image 133
pylang Avatar answered Nov 03 '25 17:11

pylang



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!