possible pairings in a set

Dave Angel davea at ieee.org
Sun Apr 5 05:09:50 CEST 2009



MRAB wrote:
> Dave Angel wrote:
>>
>>
>> Ross wrote:
>>> I'm new to python and I'm trying to come up with a function that takes
>>> a given number of players in a game and returns all possible unique
>>> pairings. Here's the code I've come up with so far, but I'm not
>>> getting the output I'd like to:
>>>
>>> def all_pairings(players):
>>>     cleanlist = []
>>>     for i in range(players):
>>>         cleanlist.append(i)
>>>     return cleanlist
>>>     start = 0
>>>     follow = start +1
>>>     finallist = []
>>>     while follow <= len(cleanlist)-1:
>>>         for player in cleanlist:
>>>             mini = cleanlist[start],cleanlist[follow]
>>>             finallist.append(mini)
>>>             follow +=1
>>>         start+=1
>>>     return finallist
>>>
>>> If I were to execute the function with all_pairings(4), I want to get
>>> the output [[0,1],[0,2],[0,3],[1,2],[1,3],[2,3]. Instead, I get
>>> [0,1,2,3] with the code I currently have. Can you guys help me out?
>>> Also, if my code is considered ugly or redundant by this community,
>>> can you make suggestions to clean it up?
>>>
>>>   
>> First problem is the return you have in the middle of the function, 
>> which returns cleanlist.  That's why you're getting [0, 1, 2, 3]
>>
>> Once you fix that, you'll find you have exceptions in the code where 
>> cleanlist[follow] doesn't work if follow is equal to 4.
>>
>> I'm afraid the code is ugly, and therefore hard to understand or 
>> fix.  Let me suggest an approach, rather than just giving you the 
>> code.  Why not create a nested for which generates two subscripts 
>> between 0 and 4, then append only those pairs in which the second is 
>> strictly greater than the first.  It won't be the quickest, but it 
>> will be easy to follow.
>>
>> No while loop, no explicit incrementing of variables, and in fact no 
>> subscripting of the lists.  Just let them supply their own values.
>>      cleanlist = range(players)             # no need for any loop, 
>> it's already a list (except in Python 3.0, in which case it's a 
>> sequence that still works just as well)
>>      finallist = []
>>      for i .....:
>>              for j...
>>                       if i<j:
>>                             append ...
>>      return finallist
>>
> Actually, cleanlist[i] == i, so it's pointless. You can do just:
>
>     finallist = []
>     for i in range(players):
>         for j in range(i + 1, players):
>             finallist.append((i, j))
>
> or, using list comprehension:
>
>     finallist = [(i, j) for i in range(players) for j in range(i + 1, 
> players)]
>
>

This looked to me like a homework assignment, or a self-assignment for a 
relative beginner in Python.  So I wanted to outline an approach, not 
provide the absolute optimum answer which might not be understood.  I 
avoided mentioning the itertools.combinations() function because you 
can't learn much from a single function call.  I avoided list 
comprehensions because they are very hard for many inexperienced python 
programmers.

I left the cleanlist in because this approach can be readily generalized 
to taking a list which isn't just a list of numbers.  Add an enumerate 
to each of the for loops, and you can readily produce all the 
combinations of whatever might be in the first list.

I debated with myself using slicing of the list for the nested for (your 
range(i+1, players) is equivalent to a slice), and decided that it would 
be harder to read. .  Clearly my nested loop iterates twice as much on 
the average as is needed, but the if is easier to read for a beginner.

Even for experienced developers, sometimes optimizing too early can make 
it hard to visualize generalizing a function.  If the function took a 
list rather than an upperlimit, it would be much more general, but how 
many could take your list comprehension and turn it into
       def  all_pairings(cleanlist):
             return   [ (a, b) for i, a in enumerate(cleanlist) for b in 
cleanlist[i+1:] ]

print all_pairings(range(2,6))
print all_pairings( ("tom", "dick", "harry", "jim") )




More information about the Python-list mailing list