Search code examples
pythoncombinationspython-itertools

Pairing people in a contest


Assume there is a some kind of a contest in which there are five boys and five girls:

boys = ["Boy1", "Boy2", "Boy3", "Boy4", "Boy5"]
girls = ["Girl1", "Girl2", "Girl3", "Girl4", "Girl5"]

Every boy is drawn against one girl and they play a game. What is the Pythonic way (probably involving itertools?) to yield all combinations of all pairs?

For example a combination could be:

combination1 = [("Boy1", "Girl1"), ("Boy2", "Girl2"), 
                ("Boy3", "Girl3"), ("Boy4", "Girl4"), ("Boy5", "Girl5")]

So Boy1 plays against Girl1 etc. If Boy1 is drawn against Girl1 then no other girl can play against him.


Solution

  • This should do the trick:

    The shuffle gives some form of randomness to which boy and girl are paired with each other

    In [115]: boys = ["Boy1", "Boy2", "Boy3", "Boy4", "Boy5"]
    
    In [116]: girls = ["Girl1", "Girl2", "Girl3", "Girl4", "Girl5"]
    
    In [117]: random.shuffle(girls)
    
    In [118]: girls
    Out[118]: ['Girl5', 'Girl4', 'Girl3', 'Girl1', 'Girl2']
    
    In [119]: for i in itertools.izip(boys, girls):
       .....:     print i
       .....:     
    ('Boy1', 'Girl5')
    ('Boy2', 'Girl4')
    ('Boy3', 'Girl3')
    ('Boy4', 'Girl1')
    ('Boy5', 'Girl2')
    

    EDIT: If you want every possible pairing, check this out:

    In [126]: boys
    Out[126]: ['Boy1', 'Boy2', 'Boy3', 'Boy4', 'Boy5']
    
    In [127]: girls
    Out[127]: ['Girl1', 'Girl2', 'Girl3', 'Girl4', 'Girl5']
    
    In [128]: [girls[i:]+girls[:i] for i in xrange(len(girls))]
    Out[128]: 
    [['Girl1', 'Girl2', 'Girl3', 'Girl4', 'Girl5'],
     ['Girl2', 'Girl3', 'Girl4', 'Girl5', 'Girl1'],
     ['Girl3', 'Girl4', 'Girl5', 'Girl1', 'Girl2'],
     ['Girl4', 'Girl5', 'Girl1', 'Girl2', 'Girl3'],
     ['Girl5', 'Girl1', 'Girl2', 'Girl3', 'Girl4']]
    
    In [129]: for combo in (itertools.izip(boys, g) for g in ( girls[i:]+girls[:i] for i in xrange(len(girls)) )):
       .....:    for pair in combo:
       .....:        print pair,
       .....:    print ''
       .....:     
    ('Boy1', 'Girl1') ('Boy2', 'Girl2') ('Boy3', 'Girl3') ('Boy4', 'Girl4') ('Boy5', 'Girl5') 
    ('Boy1', 'Girl2') ('Boy2', 'Girl3') ('Boy3', 'Girl4') ('Boy4', 'Girl5') ('Boy5', 'Girl1') 
    ('Boy1', 'Girl3') ('Boy2', 'Girl4') ('Boy3', 'Girl5') ('Boy4', 'Girl1') ('Boy5', 'Girl2') 
    ('Boy1', 'Girl4') ('Boy2', 'Girl5') ('Boy3', 'Girl1') ('Boy4', 'Girl2') ('Boy5', 'Girl3') 
    ('Boy1', 'Girl5') ('Boy2', 'Girl1') ('Boy3', 'Girl2') ('Boy4', 'Girl3') ('Boy5', 'Girl4') 
    

    EDIT 2 (fixes EDIT 1):

    >>> perms = itertools.permutations(girls)
    >>> len([tuple(p) for p in (itertools.product(boys, g) for g in perms)])
    120
    >>> perms = itertools.permutations(girls)
    >>> len(set(tuple(p) for p in (itertools.product(boys, g) for g in perms)))
    120
    

    I had to go with len because there are 120 possible pairings and I didn't want to clutter the post. This is why there is len(...) and len(set(...))