possible pairings in a set
Dave Angel
davea at ieee.org
Sat Apr 4 23:09:50 EDT 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