I have tried multiple methods in doing this but none of them seem to work
The answer comes up alphabetically instead
f=open("class2.txt", "r")
scores=myfile.readlines()
print(sorted(scores))
f.close()
['Anne, 3\n', 'Dave, 10', 'Jack, 4\n', 'Lucy, 8\n']
Also is there any way to get rid of the "/n" when it goes to the shell?
Based on the inputs and outputs, I'm guessing you're trying to sort the input names by the associated values. To sort numerically, you can either parse all the values pairs, or use a key
function with sorted
that does it for you (without storing the result anywhere). For example:
# This could be a lambda function, but I'm splitting it out for clarity
def getlinevalue(line):
intpart = line.split()[-1] # Get the last whitespace separated group (assumed to be legal integer)
return int(intpart) # Convert to int, which will sort numerically
with open("classt2.txt") as f:
stripnewlines = (line.rstrip() for line in f)
# reverse=True needed to sort highest to lowest; natural sort for int is lowest to highest
print(sorted(stripnewlines, reverse=True, key=getlinevalue))
# If the goal is to print one pair per line, replace the print above with:
for x in sorted(stripnewlines, reverse=True, key=getlinevalue):
print(x)
# Or as a one liner (require Py3, or from __future__ import print_function on Py2):
print(*sorted(stripnewlines, reverse=True, key=getlinevalue), sep="\n")
The output from print(sorted(stripnewlines, reverse=True, key=getlinevalue))
would be (modulo some whitespace; the screenshot makes it hard to tell how much whitespace is after the comma, so I'm just using a single space):
['Dave, 10', 'Lucy, 8', 'Jack, 4', 'Anne, 3']
which is what you seem to want.
Explanation of code as requested in the comments:
- In
getlinevalue
, we're splitting the provided string on whitespace (str.split
does this when not given an argument), then taking the last value from the split with [-1]
(indexing with negative numbers starts from the end). So something like 'Dave, 10'
is stored to intpart
as '10'
. Then we convert the string '10'
to its integer value with int()
and return it
with open("classt2.txt") as f:
opens the file for read and assigns the result to f
; when the indented with
block finishes, the file is closed for you (even if the block exits due to exceptions or returning from a function)
stripnewlines = (line.rstrip() for line in f)
Creates a generator expression (sort of like a lazily evaluated list comprehension that can only be iterated once) that reads a line at a time and uses str.rstrip()
to remove all trailing whitespace (e.g. the new line; you could use str.rstrip("\r\n")
to only remove the newline, not trailing tabs or spaces, but the key
function would need to be tweaked). We could use a list comprehension instead of a generator expression, but since sorted
will create the list
for us anyway, we're being lazy to avoid having both the sorted and unsorted list stored at the same time (alternatively, a list comprehension could be followed by a .sort(...)
call on the result, which would also avoid keeping two lists in memory, but .sort(...)
doesn't return anything, so we'd have more lines of code).
sorted(stripnewlines, reverse=True, key=getlinevalue)
is just like the sorted
you used in your attempt except it sorts each (rstrip
-ed) line based on the result of calling getlinevalue
on it (it only calls the key
function once per value, which is why key
is superior to cmp
; cmp
would have to convert each value log(n)
times during the sort, on average, or n log(n)
conversions total; key
converts each value once, and performs a total of n
conversions). So it sorts 'Dave, 10'
relative to 'Anne, 3'
by comparing the result of calling getlinevalue('Dave, 10')
(10
) to getlinevalue('Anne, 3')
(3
). Since numbers sort in ascending order (lowest to highest) normally (so 3
would sort before 10
) and you want descending order (highest to lowest) we also pass reverse=True
to reverse the "natural" sort of the integers.
- The final one-liner uses the "splat" operator (
*
) to convert the list resulting from the sorted
call to sequential positional arguments to print
; for Python 3's print
function (or the print
function you get in Python 2 with from __future__ import print_function
that replaces the normal print
statement of Py2), each argument is printed, with sep
printed between each argument (defaults to a single space, ' '
), and when all arguments are printed, follows it up with the value of end
(defaults to a new line, "\n"
). So that would let you print the input lines from highest to lowest on separate output lines rather than printing the representation of the sorted list on a single line.
To sort numerically by grade:
>>> sorted((line.split() for line in open('classt2.txt')), key=lambda x: int(x[1]))
[['Anne,', '3'], ['Jack,', '4'], ['Lucy,', '8'], ['Dave,', '10']]
How it works
The above code has two parts. The first reads the file and splits the lines:
>>> [line.split() for line in open('class')]
[['Anne,', '3'], ['Dave,', '10'], ['Jack,', '4'], ['Lucy,', '8']]
These lines are unsorted.
The next step is to sort the lines. This is done with sorted
with the key
option:
sorted(..., key=lambda x: int(x[1]))
The key, lambda x: int(x[1])
, takes the second element of the list, x[1]
, and converts it to an integer. In other words, sorted
sorts by the integer value of the grade.
Sorting in descending order
The above sorts in ascending order. To sort in descending order, we can add the reverse=True
option:
>>> sorted((line.split() for line in open('classt2.txt')), key=lambda x: int(x[1]), reverse=True)
[['Dave,', '10'], ['Lucy,', '8'], ['Jack,', '4'], ['Anne,', '3']]
Sorting while keeping the original whitespace
Sorting grades in ascending order:
>>> sorted(open('classt2.txt'), key=lambda x: int(x.split()[1]))
['Anne, 3\n', 'Jack, 4\n', 'Lucy, 8\n', 'Dave, 10\n']
To print that out nicely:
>>> print(''.join(sorted(open('classt2.txt'), key=lambda x: int(x.split()[1]))))
Anne, 3
Jack, 4
Lucy, 8
Dave, 10