# Python: Extract all possible mutually exclusive pairs?

## Question:

I have an assignment problem where I have N participants and need to find all possible 2-person assignments where every participant is assigned to exactly one pair.

When I use `list(combinations(range(100), 2))` I get a "flat" list of about 4000 items, each a pair in the form of (i,j).

This is not what I’m looking for; there needs to be three levels of this array:
`[ [(1,2), (3,4),...], [(1,3), (2,4),...], ... ]`

What’s the best way to accomplish this effect in Python?

You could write a recursive generator function:

``````def parings(L):
if len(L)<=2:           # only 2 elements, single pair
yield [tuple(L)]
return
for j in range(1,len(L)):                # first element paired with every other
for rest in parings(L[1:j]+L[j+1:]): # with all pairings of remaining elements
yield [(L[0],L[j])] + rest

for p in parings([1,2,3,4,5,6]): print(p)

[(1, 2), (3, 4), (5, 6)]
[(1, 2), (3, 5), (4, 6)]
[(1, 2), (3, 6), (4, 5)]
[(1, 3), (2, 4), (5, 6)]
[(1, 3), (2, 5), (4, 6)]
[(1, 3), (2, 6), (4, 5)]
[(1, 4), (2, 3), (5, 6)]
[(1, 4), (2, 5), (3, 6)]
[(1, 4), (2, 6), (3, 5)]
[(1, 5), (2, 3), (4, 6)]
[(1, 5), (2, 4), (3, 6)]
[(1, 5), (2, 6), (3, 4)]
[(1, 6), (2, 3), (4, 5)]
[(1, 6), (2, 4), (3, 5)]
[(1, 6), (2, 5), (3, 4)]
``````

With N=10 you still get a reasonable number of patterns:

``````L = list(range(10))
print(sum(1 for _ in parings(L))) # 945
``````

but it gets unmanageable real quick:

``````L = list(range(18))
print(sum(1 for _ in parings(L))) # 34,459,425
``````

To decide on the size of your toy problem, you could adapt the recursive function to compute the number of results like this:

``````def pairingCount(N):
if N<=2: return 1
return (N-1) * pairingCount(N-2)

print(pairingCount(18)) # 34,459,425
``````

Mathematically, the count can be expressed using factorials:

``````                n!
count =  ----------------
(n/2)! * 2^(n/2)
``````
``````def find_assignments(N):
assignments = []
size = N//2
elems = list(range(N))
C = list(combinations(elems, size))
for c in C:
A = set(c)
B = list(set(elems).difference(A))
P = list(permutations(B))
for p in P:
edges = [(c[i], p[i]) for i in range(size)]
assignments.append(edges)

return assignments
``````
Categories: questions
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.