I have a list of elements, that I would like to group (of size 2,3,4 etc.) and find some unique combinations in each iteration. I have the following snippet, that forms combinations of size group_size of members.
import random
from itertools import zip_longest
members = ['A', 'B', 'C', 'D', 'E', 'F', 'U', 'V', 'W', 'X', 'Y', 'Z']
group_size = 2
for i in range(10):
random.shuffle(members)
pairs_loc = [iter(members)] * group_size
pairs = zip_longest(*pairs_loc)
print(*pairs)
Honestly I'm not sure I understood correctly what you want to do, but let me try, maybe it is useful to you all the same.
For the first point Python already has what (I believe that) you're looking for: itertools.combinations
.
For the second point we need some code. One note: I'm sure you realize that with this second requirement you will have some cases when not all members appear in at least one combination: e.g., with 12 members and a groupsize > 6
.
The code:
def select_combos(members, groupsize):
assert groupsize > 1
shuffle(members)
if groupsize == 2:
return list(combinations(members, 2))
finalcombos = []
usedcombos = []
for c in combinations(members, groupsize):
tempcombos = list(combinations(c, 2))
for c2 in tempcombos:
if c2 in usedcombos:
break
else:
usedcombos += tempcombos
finalcombos.append(c)
return finalcombos
m = ['A', 'B', 'C', 'D', 'E', 'F', 'U', 'V', 'W', 'X', 'Y', 'Z']
select_combos(m, 2)
[('C', 'A'), ('C', 'Z'), ('C', 'Y'), ('C', 'E'), ('C', 'W'), ('C', 'B'), ('C', 'U'), ('C', 'X'), ('C', 'D'), ('C', 'V'), ('C', 'F'), ('A', 'Z'), ('A', 'Y'), ('A', 'E'), ('A', 'W'), ('A', 'B'), ('A', 'U'), ('A', 'X'), ('A', 'D'), ('A', 'V'), ('A', 'F'), ('Z', 'Y'), ('Z', 'E'), ('Z', 'W'), ('Z', 'B'), ('Z', 'U'), ('Z', 'X'), ('Z', 'D'), ('Z', 'V'), ('Z', 'F'), ('Y', 'E'), ('Y', 'W'), ('Y', 'B'), ('Y', 'U'), ('Y', 'X'), ('Y', 'D'), ('Y', 'V'), ('Y', 'F'), ('E', 'W'), ('E', 'B'), ('E', 'U'), ('E', 'X'), ('E', 'D'), ('E', 'V'), ('E', 'F'), ('W', 'B'), ('W', 'U'), ('W', 'X'), ('W', 'D'), ('W', 'V'), ('W', 'F'), ('B', 'U'), ('B', 'X'), ('B', 'D'), ('B', 'V'), ('B', 'F'), ('U', 'X'), ('U', 'D'), ('U', 'V'), ('U', 'F'), ('X', 'D'), ('X', 'V'), ('X', 'F'), ('D', 'V'), ('D', 'F'), ('V', 'F')]
select_combos(m, 5)
[('W', 'V', 'C', 'U', 'E'), ('W', 'A', 'X', 'B', 'F'), ('V', 'A', 'D', 'Y', 'Z')]
EDIT Now that it's clearer, the request for group size 2 is equivalent to scheduling a round-robin tournament, so we can use the standard circle method here.
One quick and dirty implementation of the rotation:
def rotate(roster):
half = (len(roster)+1)//2
t=roster[1]
roster[1] = roster[half]
for j in range(half, len(roster)-1):
roster[j] = roster[j+1]
roster[-1] = roster[half-1]
for j in range(half-1, 1, -1):
roster[j] = roster[j-1]
roster[2] = t
for i in range(half):
print(f'{roster[i]}-{roster[i+half]} ', end = '')
print()
members = ['A', 'B', 'C', 'D', 'E', 'F', 'U', 'V', 'W', 'X', 'Y', 'Z']
shuffle(members)
for r in range(len(members)):
rotate(members)
At each iteration this will rotate the roster one step and print the pairings. Note that at the n-th iteration the roster, and hence the pairings, will be the same as at the start.