Как найти среднее арифметического словаря python через добавление нового ключа

Выполнял задание по словарям в python, решил сверх добавить вывод самого среднего арифметического через добавление нового ключа avg в полученный словарь best_students

Само задание: Есть список словарей со студентами students. В каждом объекте есть имя и фамилия студента, а также список оценок (целых чисел). Нужно написать функцию get_best_students, которая берёт студентов и находит того, у кого средний балл наибольший. Возвращает функция список студентов с лучшим баллом best_students

students = [
{"name": "John", "surname": "Doe", "grades": [5, 5, 4, 4]},
{"name": "Jane", "surname": "Doe", "grades": [4, 3, 4, 3, 5]},
{"name": "Bill", "surname": "Gates", "grades": [5, 5, 5, 3]},
{"name": "Steve", "surname": "Jobs", "grades": [3, 5, 4, 3, 3, 5]},
{"name": "Guido", "surname": "Van Rossum", "grades": [5, 3, 5, 4, 5, 5, 3, 5]},
{"name": "Elon", "surname": "Musk", "grades": None} ]

Код решения:

    def get_best_students(*, students: list[dict]) -> list[dict]:
    best_students = []
    best_average_grade = 0
    for student in students:
        grades = student["grades"]
        if grades is None:
            average_grade = 0
        else:
            average_grade = sum(grades) / len(grades)
        if average_grade > best_average_grade:
            best_average_grade = average_grade
            best_students = [student]
        elif average_grade == best_average_grade:
            best_students.append(student)
            best_students.append('avg')  # Мой созданный ключ avg
    return best_students
print(get_best_students(students=students))  # Outputs [{'name': 'John', 'surname': 'Doe', 'grades': [5, 5, 4, 4]}, {'name': 'Bill', 'surname': 'Gates', 'grades': [5, 5, 5, 3]}, 'avg']

Я смог добавить новый ключ avg в словарь best_students, но не могу понять, как передать ему переменную avg_grades, чтобы вывести ср. арифметическое оценок в best_students

Также при попытке добавить такую строку: best_students['avg'] = avg_grade выдаёт ошибку TypeError: list indices must be integers or slices, not str

Изменение скобок не даёт результата: cannot assign to function call here. Maybe you meant '==' instead of '='? или же 'list' object is not callable. Может нужна новая функция? Как это всё связать..


Ответы (2 шт):

Автор решения: krabnerab

best_students - это список (list), который изначально содержит словари студентов

.append() - метод списка, который добавляет новый элемент в конец списка

'avg' - это строка (string), а не ключ словаря

Результат выполнения этой (best_students.append('avg')) строки:

До выполнения:

best_students = [{'name': 'John', 'surname': 'Doe', 'grades': [5,5,4,4]}]

После выполнения:

best_students = [
    {'name': 'John', 'surname': 'Doe', 'grades': [5,5,4,4]},
    'avg'  # ← это строка, а не словарь и не ключ!
]

вот решение которое я предлагаю:

def get_best_students(*, students: list[dict]) -> list[dict]:
    best_students = []
    best_average_grade = 0

    for student in students:
        grades = student["grades"]
        if grades is None:
            average_grade = 0
        else:
            average_grade = sum(grades) / len(grades)

        # Добавляем средний балл как ключ в словарь студента (опционально)
        student_with_avg = student.copy()
        student_with_avg['avg'] = round(average_grade, 2)

        if average_grade > best_average_grade:
            best_average_grade = average_grade
            best_students = [student_with_avg]
        elif average_grade == best_average_grade:
            best_students.append(student_with_avg)

    return best_students


students = [
    {"name": "John", "surname": "Doe", "grades": [5, 5, 4, 4]},
    {"name": "Jane", "surname": "Doe", "grades": [4, 3, 4, 3, 5]},
    {"name": "Bill", "surname": "Gates", "grades": [5, 5, 5, 3]},
    {"name": "Steve", "surname": "Jobs", "grades": [3, 5, 4, 3, 3, 5]},
    {"name": "Guido", "surname": "Van Rossum", "grades": [5, 3, 5, 4, 5, 5, 3, 5]},
    {"name": "Elon", "surname": "Musk", "grades": None}
]

result = get_best_students(students=students)
print(result)
→ Ссылка
Автор решения: CrazyElf

Так то никто вам не запрещает возвращать из функции кортеж из максимального среднего и списка студентов. Ну и код можно гораздо короче написать, используя списковые сокращения:

def avg(lst):
    return 0 if lst is None else sum(lst)/len(lst)

def get_best_students(*, students: list[dict]) -> tuple[float, list[dict]]:
    max_avg = max(avg(s['grades']) for s in students)
    return max_avg, [s for s in students if avg(s['grades']) == max_avg]

print(*get_best_students(students=students), sep='\n')

# 4.5
# [{'name': 'John', 'surname': 'Doe', 'grades': [5, 5, 4, 4]}, {'name': 'Bill', 'surname': 'Gates', 'grades': [5, 5, 5, 3]}]

И вам уже объяснили, что список и словарь - это разное, в список нельзя добавлять элементы по ключу, это функция словаря.

→ Ссылка