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") )

--
http://mail.python.org/mailman/listinfo/python-list

Reply via email to