How do I sort data highest to lowest in Python fro

2019-06-14 18:04发布

问题:

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?

回答1:

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:

  1. 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
  2. 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)
  3. 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).
  4. 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.
  5. 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.


回答2:

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