0

I wish to sort a list by the first value in each tuple, however my code does not produce any real sorted list, although the order of the list does change. My list contains tuples with a value for the 'PlayerCode' which is a unique key for each player. And 'Average Points' which is the average amount of points that the player scores each game. I wish to sort this list by 'Average Points' although I cant seem to get it right. Here is my code

def getKey(item):
        return item[0]
def sortByPoints():
    foundPlayers = []
    with open ('PlayerList.csv') as csvfile:
        reader = csv.DictReader(csvfile)
        for row in reader:
            foundPlayers.append((row['Average PTS'], row['PlayerCode']))
    print(foundPlayers)
    sortedPlayers = sorted(foundPlayers, key = getKey)

    print (sortedPlayers)

Like I said, this does change the order of the list, but not the way im looking for, nor can I see any real pattern to which it has changed it to. I am using python 3.4

Here is the output of the two lists

unsorted: [('7', '1'), ('8', '2'), ('4', '3'), ('28', '4'), ('0', '5'), ('18', '6'), ('10', '7'), ('9', '8'), ('10', '9'), ('2', '10'), ('4', '11'), ('2', '12'), ('3', '13'), ('4', '14'), ('2', '15')]

sorted: [('0', '5'), ('10', '7'), ('10', '9'), ('18', '6'), ('2', '10'), ('2', '12'), ('2', '15'), ('28', '4'), ('3', '13'), ('4', '3'), ('4', '11'), ('4', '14'), ('7', '1'), ('8', '2'), ('9', '8')]

H_Lev1
  • 253
  • 4
  • 18
  • 2
    Note that sorting by the first value is the **default sort** for tuples. Beyond that, without a [mcve], it's unclear what your problem is. – jonrsharpe Nov 07 '16 at 20:00
  • 1
    you want to sort then based on the integer value, they're Strings at the moment, so you can just change the getKey function to return int(item[0]) – chatton Nov 07 '16 at 20:07
  • You can use strings if you really want to, just sort using `float` - see http://stackoverflow.com/a/17474264/2178980 (actually, the above comment will also do the trick) – Eugene Nov 07 '16 at 20:10

5 Answers5

3

You can use itemgetter imported from the built in module operator

Example code:

from operator import itemgetter

tuples = [(10, 3), (1, 4), (5, 4)]
sorted_tuples = sorted(tuples, key=itemgetter(0))

print(sorted_tuples)

Output:

[(1, 4), (5, 4), (10, 3)]
O. Edholm
  • 2,044
  • 2
  • 12
  • 13
0

The problem is that you have strings and so it's sorting them alphabetically. Convert to integers:

foundPlayers.append((int(row['Average PTS']), int(row['PlayerCode'])))
Alex Hall
  • 34,833
  • 5
  • 57
  • 89
0

row['Average PTS'] and row['Player Code'] return strings. Python will compare strings with (possibly) surprising results

>>> '6' > '42'
True

Convert row['Average PTS'] and row['Player Code'] using int.

Mark Hannel
  • 767
  • 5
  • 12
0

You may use lambda function as key to sorted as:

sorted(my_list, key=lambda x: (int(x[1]), int(x[0])))

Here:

  • the list will be sorted based on the content at 1st index. In case of same value, list will be sorted based on 0th index.
  • Also you need to type-cast the values in tuple to int. As sorted does the lexicographically sorting. That means, for string values, '11' will come before '2'.

Below is the sample example:

>>> my_list = [('7', '1'), ('8', '2'), ('4', '3'), ('28', '4'), ('0', '5'), ('18', '6'), ('10', '7'), ('9', '8'), ('10', '9'), ('2', '10'), ('4', '11'), ('2', '12'), ('3', '13'), ('4', '14'), ('2', '15')]
>>> sorted(my_list, key=lambda x: (int(x[1]), int(x[0])))                                  
[('7', '1'), ('8', '2'), ('4', '3'), ('28', '4'), ('0', '5'), ('18', '6'), ('10', '7'), ('9', '8'), ('10', '9'), ('2', '10'), ('4', '11'), ('2', '12'), ('3', '13'), ('4', '14'), ('2', '15')]
Moinuddin Quadri
  • 46,825
  • 13
  • 96
  • 126
0

Here is my answer. I believe in maintaining the OP's original code as much as possible to make as fewer assumptions as possible. What if it is a requirement to have strings? Also, with as fewer additional imports as possible. Thus my solution would be:

def sortByPoints():
    foundPlayers = []
    with open ('PlayerList.csv') as csvfile:
        reader = csv.DictReader(csvfile)
        for row in reader:
            foundPlayers.append((row['Average PTS'], row['PlayerCode']))
    print(foundPlayers)
    sortedPlayers = sorted(foundPlayers, key=lambda x: float(x[0]))
    print(sortedPlayers)

Remove redundant getKey function, and use a lambda instead for neatness. Using float just in case it may be required in the future (as you are only using for comparison; using int only limits you and has no advantages over float).

I also believe in copy and paste code ;)


FYI, to change direction:

sortedPlayers = sorted(foundPlayers, key=lambda x: float(x[0]), reverse=True)

Also note that, if the intention is indeed for integers only, then you should do as everyone suggests and convert your elements to int:

def sortByPoints():
    foundPlayers = []
    with open ('PlayerList.csv') as csvfile:
        reader = csv.DictReader(csvfile)
        for row in reader:
            foundPlayers.append((int(row['Average PTS']), int(row['PlayerCode'])))
    print(foundPlayers)
    sortedPlayers = sorted(foundPlayers, key=lambda x: x[0])
    print(sortedPlayers)
Eugene
  • 1,539
  • 12
  • 20