简体   繁体   中英

Python: Sorting list containing tuples

I am still learning Python and I have been trying to sort this problem for hours but somehow cannot get it working: Suppose we have a list of tuples containing names and grades:

[("Mark", [5,4,1,2,4,3]), ("John", [1,2,3,1,2,1]), ("Patrick", [1,3,5,1,2,4])]

And we want to get this output:

[("John", [1,2,3,1,2,1]), ("Patrick", [1,3,5,1,2,4]), ("Mark", [5,4,1,2,4,3])]

, where the original list is is sorted in ascending order of students' marks score (suppose we get marks score by discarding the highest mark and adding all remaining marks together). Ie John has marks 1,2,3,1,2,1, so we discard mark 3 and add 1+2+1+2+1 together, which gives us 7.

This task wouldnt be problem at all, if I wasnt required to get that output with all their original marks. I wrote this function:

def sortedFinalRes(input):
finalRes = 0
sortedRes = []
b = []
for i in range(0, len(input)):
    total = 0
    a = sorted(input[i][1], key = lambda x: x)
    a.pop()
    sortedRes += input[i][0], a
    total = sum(sortedRes[i*2+1])
    b += (sortedRes[i*2], total)
    c = sorted(b, key = lambda x: str(x))
print(sortedRes)
print(b)

, where I basically at first sort marks of each student so that I can then discard the highest one by using pop() and then I sum all remaining ones, which gives me marks score. Then I sort it according to marks score, but the output is required to be sorted, but with original marks, not with the mark score. Any ideas appreciated! Cheers

We can define a scoring function like this:

def score(x): sum(x) - max(x)       

This computes your so-called "marks score" by summing the scores and throwing out the max score. We'll then use it as a key for sorting, making sure to give it the second element of the tuple:

In [4]: sorted(d, key=lambda x: score(x[1]))                                                                                                                 
Out[4]: 
[('John', [1, 2, 3, 1, 2, 1]),
 ('Patrick', [1, 3, 5, 1, 2, 4]),
 ('Mark', [5, 4, 1, 2, 4, 3])]
def sort_key(item):
    name,scores = item
    return sum(scores)-max(scores)
print sorted(students,key=sort_key)

you could easily do it with a single lambda as shown below ... I just did this for added verbosity

you can refuse from max value by sorted(x[1])[:-1] that first sort the list and slice from beginning to highest:

>>> sorted (l,key=lambda x : sum(sorted(x[1])[:-1]))
[('John', [1, 2, 3, 1, 2, 1]), ('Patrick', [1, 3, 5, 1, 2, 4]), ('Mark', [5, 4, 1, 2, 4, 3])]

answers benchmark :

>>> s="""l=[("Mark", [5,4,1,2,4,3]), ("John", [1,2,3,1,2,1]), ("Patrick", [1,3,5,1,2,4])]
... sorted (l,key=lambda x : sum(sorted(x[1])[:-1]))"""
>>> timeit.timeit(stmt=s, number=100000)
0.407818078994751

>>> s="""l=[("Mark", [5,4,1,2,4,3]), ("John", [1,2,3,1,2,1]), ("Patrick", [1,3,5,1,2,4])]
... sorted(l, key=lambda x: sum(x[1]) - max(x[1]))"""
>>> timeit.timeit(stmt=s, number=100000)
0.3033828830718994

>>> s="""l=[("Mark", [5,4,1,2,4,3]), ("John", [1,2,3,1,2,1]), ("Patrick", [1,3,5,1,2,4])]
... def sort_key(item):
...     name,scores = item
...     return sum(scores)-max(scores)
... sorted(l,key=sort_key)"""
>>> timeit.timeit(stmt=s, number=100000)
0.2999439334869385

As you can see there no much difference between all the answers , any way Joran Beasley's answer is the best !

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM