0

I need to write a function sort_gradebook(gradebook), which has next arguments: [first_name, last_name, grade_1, grade_2, ..., grade_n, final_grade]. Function must sort by:

  • Final grade
  • If final grades are equal - by first grade
  • If first grades are equal - by second grade, etc
  • If all grades are equal - by second name
  • If second names are equal - by name.

Everything I could do:

from operator import itemgetter

def sort_gradebook(*gradebook):
    length = len([str(i) for i in gradebook[0]])
    a = [i for i in range(length)]
    for i in a:
        s = sorted(gradebook, key = itemgetter(i))

    return s

For test:

from itertools import permutations

def test_sort(inp, outp):
    for i in permutations(inp):
        assert sort_gradebook(list(i)) == outp

test_sort([['Alice', 'Smith', 2, 3, 4],
    ['John', 'Smith', 2, 3, 5]], [['John', 'Smith', 2, 3, 5],
    ['Alice', 'Smith', 2, 3, 4]
])
  • So, the number of grades can change? – Anwarvic Jun 01 '20 at 08:50
  • You miss to `reverse` as John has higher final grade and comes first – azro Jun 01 '20 at 09:02
  • @Mandera No, it's not. I already saw thos answers. They are good for 2 arguments, but doesn't work with more... or I didn't get how to use it for multiple arguments... anyway, I would be thankful, if someone can explain, how to apply that answer to my question. – Sultan Tapi Jun 01 '20 at 09:04
  • @SultanTapi Oh okay I see how you can think that. The thing you missed is that the `key` parameter of `sort` can handle a tuple, which means that you can have infinite keys, not only two like they use in the example. – Mandera Jun 01 '20 at 09:47

1 Answers1

1

Sorting

  • you want to sort on multiple parameters, that are the different indices. You can use itemgetter(0,1,2), and in your case itemgetter(4,3,2,1,0) which need to be built dynamically regarding the size

  • add reverse=True to get John, who has higher final grade, before Alice

def sort_gradebooks(*gradebooks):
    nb_attributes = len(gradebooks[0])
    s = itemgetter(*[i for i in range(nb_attributes - 1, -1, -1)]) # itemgetter(4,3,2,1,0)
    return sorted(gradebooks, key=s, reverse=True)

Call it

You need to call the sort with *i and i to pass the flatten the parameters and not pass one list, but rather multiple items

def test_sort(inp, outp):
    for i in permutations(inp):
        print(sort_gradebooks(*i) == outp)

print(sort_gradebooks(*[['Alice', 'Smith', 2, 3, 4], ['John', 'Smith', 2, 3, 5]])) # John / Alice because final grade
print(sort_gradebooks(*[['Alice', 'Smith', 2, 3, 5], ['John', 'Smith', 2, 3, 5]])) # John / Alice because name
print(sort_gradebooks(*[['Alice', 'Smith', 2, 5, 5], ['John', 'Smith', 2, 3, 5]])) # Alice / John because 2ng grade
azro
  • 53,056
  • 7
  • 34
  • 70
  • Thank you! Bueatiful code! Could you please explain, itemgetter(4,3,2,1,0) starts to sort from ind(4)? – Sultan Tapi Jun 01 '20 at 11:56
  • @SultanTapi 0,1,2,3,4 are the indices of each value of `['Alice', 'Smith', 2, 3, 4]` – azro Jun 01 '20 at 12:02
  • i know. s = itemgetter(*[i for i in range(nb_attributes - 1, -1, -1)]) # itemgetter(4,3,2,1,0) - sorting starts from index 4, then 3, 2, 1 and 0? – Sultan Tapi Jun 01 '20 at 14:08
  • @SultanTapi yes – azro Jun 01 '20 at 14:09
  • Thanks! last question: i read somewhere, that if you want to sort by several arguments, you must to start from earliest to the latest, for example in ['Alice', 'Smith', 1, 3, 5], ['John', 'Smith', 2, 3, 5], first you must sort by ind(0), then(1), etc. is it right? if yes, how your sorting works, if it starts from ind(4)? – Sultan Tapi Jun 01 '20 at 14:21
  • @SultanTapi you said you want to start by sorting n Final grade, and end on Name so .. ? – azro Jun 01 '20 at 14:56
  • exactly. before i started this task, i read rules, how to sort. they wrote about such cases, like, if you need to sort multiple arguments beginning from index(last), you need to sort first index(0), then index(1), ..., index(last). thats why i was surprised, when saw your solution, because your code starts to sort from ind(last). i guess, the rule i read wasn't correct? – Sultan Tapi Jun 01 '20 at 15:05
  • @SultanTapi If you want to sort by name then by final grade you would have done `itemgetter(0,4)` OR, by grade and if grade same by name : `itemgetter(4,0)` you asked by **final grade** first, so it comes fist in the itemgetter – azro Jun 01 '20 at 15:16