Функция, которая сортирует по нескольким аргументам
Помогите пожалуйста с решением задачи:
Написать функцию sort_gradebook(gradebook), принимающую на вход некую ведомость в виде списка, элементами которого являются списки такого вида: [first_name, last_name, grade_1, grade_2, ..., grade_n, final_grade], где first_name — имя студента, last_name — его фамилия, grade_1, ..., grade_n — оценки студента по контрольным от 1 до n (число n — общее число контрольных, оно одинаковое для конкретного gradebook, но заранее не известно), final_grade — итоговая оценка. Функция должна отсортировать gradebookследующим образом (и вернуть его отсортированным):
- По итоговой оценке
- При совпадении итоговой оценки — по оценке за первую контрольную
- При совпадении всего предыдущего — по оценке за вторую контрольную
- При совпадении всего предыдущего — по оценке за третью контрольную (и т.д. пока контрольные не закончатся)
- При совпадении всех оценок — по фамилии *При совпадении всех оценок и фамилии — по имени
Примеры:
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]
])
test_sort([
['Alice', 'Smith', 2, 3, 4],
['John', 'Smith', 2, 3, 4]
], [
['Alice', 'Smith', 2, 3, 4],
['John', 'Smith', 2, 3, 4]
])
Вот, что я смог сделать:
def function(*examples):
length = len([str(i) for i in examples[0]])
a = [i for i in range(length)]
for i in a:
s = sorted(examples, key = itemgetter(i))
return s
В какой бы последовательности я не сортировал (с 0 по 4, или с 4 по 0) - никак не получается соответствовать условиям задачи. Не знаю что делать.
Благодарю.
Ответы (1 шт):
Если нужно отсортировать все списки по убыванию, тогда все просто:
import operator
def sort_gradebook(gradebook):
return sorted(
gradebook,
key=operator.itemgetter(-1, slice(2, -1), 1, 0),
reverse=True
)
здесь -1, slice(2, -1), 1, 0:
- последний элемент, итоговая оценка;
- срез для оценок, сколько бы их ни было;
- второй элемент, фамилия;
- первый элемент (с индексом 0), имя ученика
Но, если я правильно понял вопрос, задача усложняется тем, что оценки должны быть в порядке убывания (от высоких к низким), а фамилии и имена - по возрастанию, т.е. в алфавитном порядке?
В таком случае есть смысл в функции, принимающей как критерии сортировки, так и направление для каждого из них (вдруг, завтра изменят условие задачи):
def sort_gradebook(gradebook, rev_descending):
new_gradebook = gradebook.copy()
for key, reverse in reversed(rev_descending):
new_gradebook.sort(key=operator.itemgetter(key), reverse=reverse)
return new_gradebook
где в качестве параметра rev_descending передается итерируемый объект (список, кортеж):
[[-1, True], [slice(2, -1), True], [1, False], [0, False]]
И, наконец, неплохо было бы проверить работоспособность:
import operator
import unittest
def sort_gradebook(gradebook, rev_descending):
new_gradebook = gradebook.copy()
for key, reverse in reversed(rev_descending):
new_gradebook.sort(key=operator.itemgetter(key), reverse=reverse)
return new_gradebook
class Tests(unittest.TestCase):
def test_sort_gradebook(self):
self.assertEqual(sort_gradebook(
[
['Alice', 'Smith', 2, 3, 4],
['John', 'Smith', 2, 3, 5]
],
[[-1, True], [slice(2, -1), True], [1, False], [0, False]]
),
[
['John', 'Smith', 2, 3, 5],
['Alice', 'Smith', 2, 3, 4]
]
)
self.assertEqual(sort_gradebook(
[
['John', 'Smith', 2, 3, 4],
['Alice', 'Smith', 2, 3, 4],
],
[[-1, True], [slice(2, -1), True], [1, False], [0, False]]
),
[
['Alice', 'Smith', 2, 3, 4],
['John', 'Smith', 2, 3, 4]
]
)
self.assertEqual(sort_gradebook(
[
['John', 'Smith', 4, 4, 5, 4, 4, 4],
['Alice', 'Smith', 4, 4, 5, 4, 4, 4],
['Lima', 'Navarro', 5, 4, 5, 4, 5, 4],
['John', 'Hopkins', 2, 3, 3, 4, 3, 3],
['Paolo', 'Maroni', 2, 1, 2, 3, 5, 3],
['Ali', 'Baba', 4, 5, 5, 5, 5, 5],
['Cun', 'Baba', 4, 5, 5, 5, 5, 5],
['Bar', 'Baba', 5, 5, 5, 5, 5, 5]
],
[[-1, True], [slice(2, -1), True], [1, False], [0, False]]
),
[
['Bar', 'Baba', 5, 5, 5, 5, 5, 5],
['Ali', 'Baba', 4, 5, 5, 5, 5, 5],
['Cun', 'Baba', 4, 5, 5, 5, 5, 5],
['Lima', 'Navarro', 5, 4, 5, 4, 5, 4],
['Alice', 'Smith', 4, 4, 5, 4, 4, 4],
['John', 'Smith', 4, 4, 5, 4, 4, 4],
['John', 'Hopkins', 2, 3, 3, 4, 3, 3],
['Paolo', 'Maroni', 2, 1, 2, 3, 5, 3]
]
)
if __name__ == '__main__':
unittest.main()
После запуска файла в терминале $ python gradebook.py:
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK