Last version

This commit is contained in:
stud203998 2026-04-14 22:02:46 +03:00
parent fab3f1f6e4
commit fc869c60df
3 changed files with 330 additions and 0 deletions

25
data/report.json Normal file
View File

@ -0,0 +1,25 @@
{
"total_students": 6,
"average_grade_all": 82.83,
"top_student": {
"id": 4,
"name": "Елена Смирнова",
"courses": [
"Программирование на Python",
"Базы данных"
],
"grades": [
100.0,
98.0,
97.0
],
"avg_grade": 98.33333333333333
},
"course_popularity": {
"Математика": 3,
"Программирование на Python": 4,
"Физика": 3,
"Английский язык": 2,
"Базы данных": 1
}
}

View File

@ -0,0 +1,38 @@
[
{
"id": 1,
"name": "Иван Петров",
"courses": ["Математика", "Программирование на Python", "Физика"],
"grades": [85.0, 92.0, 78.0]
},
{
"id": 2,
"name": "Мария Сидорова",
"courses": ["Программирование на Python", "Английский язык"],
"grades": [95.0, 88.0, 91.0]
},
{
"id": 3,
"name": "Алексей Иванов",
"courses": ["Математика", "Физика"],
"grades": [72.0, 68.0, 74.0]
},
{
"id": 4,
"name": "Елена Смирнова",
"courses": ["Программирование на Python", "Базы данных"],
"grades": [100.0, 98.0, 97.0]
},
{
"id": 5,
"name": "Дмитрий Козлов",
"courses": ["Математика"],
"grades": [60.0, 65.0]
},
{
"id": 6,
"name": "Ольга Новикова",
"courses": ["Программирование на Python", "Английский язык", "Физика"],
"grades": [88.0, 94.0, 82.0, 90.0]
}
]

View File

@ -0,0 +1,267 @@
import json
import csv
import os
from typing import List, Dict, Any
# ---------- 1. Загрузка данных ----------
def load_students(filepath: str) -> List[Dict[str, Any]]:
"""
Загружает данные из файла (CSV или JSON).
Возвращает список словарей студентов.
"""
if not os.path.exists(filepath):
raise FileNotFoundError(f"Файл {filepath} не найден.")
if filepath.endswith('.json'):
with open(filepath, 'r', encoding='utf-8') as f:
data = json.load(f)
# Приведение к единому формату (список словарей)
if isinstance(data, dict) and 'students' in data:
return data['students']
return data
elif filepath.endswith('.csv'):
students = []
with open(filepath, 'r', encoding='utf-8') as f:
reader = csv.DictReader(f)
for row in reader:
# Преобразование полей
student = {
'id': int(row['id']),
'name': row['name'],
'courses': row['courses'].split(';') if row['courses'] else [],
'grades': [float(x) for x in row['grades'].split(';')] if row['grades'] else []
}
students.append(student)
return students
else:
raise ValueError("Неподдерживаемый формат файла. Используйте .json или .csv")
# ---------- 2. Валидация одного студента ----------
def validate_student_data(student: Dict[str, Any]) -> bool:
"""
Проверяет корректность данных студента.
Возвращает True, если все поля валидны.
"""
required_keys = {'id', 'name', 'courses', 'grades'}
if not required_keys.issubset(student.keys()):
return False
# Проверка id
if not isinstance(student['id'], int) or student['id'] <= 0:
return False
# Проверка имени
if not isinstance(student['name'], str) or len(student['name'].strip()) == 0:
return False
# Проверка курсов (должен быть список строк)
if not isinstance(student['courses'], list):
return False
for course in student['courses']:
if not isinstance(course, str):
return False
# Проверка оценок (список чисел от 0 до 100)
if not isinstance(student['grades'], list):
return False
for grade in student['grades']:
if not isinstance(grade, (int, float)) or not (0 <= grade <= 100):
return False
return True
# ---------- 3. Средний балл ----------
def calculate_average_grade(grades: List[float]) -> float:
"""
Возвращает среднее арифметическое списка оценок.
Для пустого списка возвращает 0.0.
"""
if not grades:
return 0.0
return sum(grades) / len(grades)
# ---------- 4. Добавление студента ----------
def add_student(students: List[Dict[str, Any]], student: Dict[str, Any]) -> List[Dict[str, Any]]:
"""
Добавляет нового студента, если id уникален.
Возвращает обновлённый список.
"""
if any(s['id'] == student['id'] for s in students):
print(f"Предупреждение: студент с id={student['id']} уже существует. Добавление отменено.")
return students
students.append(student)
return students
# ---------- 5. Удаление студента ----------
def remove_student(students: List[Dict[str, Any]], student_id: int) -> List[Dict[str, Any]]:
"""
Удаляет студента по id. Возвращает новый список.
"""
new_list = [s for s in students if s['id'] != student_id]
if len(new_list) == len(students):
print(f"Предупреждение: студент с id={student_id} не найден.")
return new_list
# ---------- 6. Топ-студенты по порогу ----------
def find_top_performers(students: List[Dict[str, Any]], threshold: float) -> List[Dict[str, Any]]:
"""
Возвращает список студентов со средним баллом >= threshold,
отсортированный по убыванию среднего балла.
"""
# Вычисляем средний балл для каждого студента
students_with_avg = []
for s in students:
avg = calculate_average_grade(s['grades'])
students_with_avg.append((avg, s))
# Фильтруем и сортируем
filtered = [(avg, s) for avg, s in students_with_avg if avg >= threshold]
filtered.sort(key=lambda x: x[0], reverse=True)
return [s for _, s in filtered]
# ---------- 7. Студенты по курсу ----------
def get_students_by_course(students: List[Dict[str, Any]], course_name: str) -> List[Dict[str, Any]]:
"""
Возвращает список студентов, изучающих указанный курс.
"""
return [s for s in students if course_name in s['courses']]
# ---------- 8. Генерация отчёта ----------
def generate_report(students: List[Dict[str, Any]]) -> Dict[str, Any]:
"""
Формирует статистический отчёт.
"""
if not students:
return {
"total_students": 0,
"average_grade_all": 0.0,
"top_student": None,
"course_popularity": {}
}
total = len(students)
# Средний балл всех студентов
all_avgs = [calculate_average_grade(s['grades']) for s in students]
avg_all = sum(all_avgs) / total if total else 0.0
# Лучший студент
max_avg = max(all_avgs)
top_student = next(s for s in students if calculate_average_grade(s['grades']) == max_avg)
# Популярность курсов
course_pop = {}
for s in students:
for c in s['courses']:
course_pop[c] = course_pop.get(c, 0) + 1
return {
"total_students": total,
"average_grade_all": round(avg_all, 2),
"top_student": top_student,
"course_popularity": course_pop
}
# ---------- 9. Сортировка студентов по среднему баллу ----------
def sort_students_by_grade(students: List[Dict[str, Any]], reverse: bool = False) -> List[Dict[str, Any]]:
"""
Возвращает новый список, отсортированный по среднему баллу.
reverse=True по убыванию, иначе по возрастанию.
"""
return sorted(students, key=lambda s: calculate_average_grade(s['grades']), reverse=reverse)
# ---------- 10. Сохранение отчёта в JSON ----------
def save_report(report: Dict[str, Any], filepath: str) -> None:
"""
Сохраняет отчёт в файл в формате JSON.
"""
# Преобразуем top_student в сериализуемый словарь (исключаем функции)
serializable_report = report.copy()
if 'top_student' in serializable_report and serializable_report['top_student'] is not None:
# Создаём копию без лишних полей
top = serializable_report['top_student'].copy()
serializable_report['top_student'] = top
with open(filepath, 'w', encoding='utf-8') as f:
json.dump(serializable_report, f, indent=2, ensure_ascii=False)
# ---------- Основная функция main() ----------
def main():
# Убедимся, что папка data существует
os.makedirs("data", exist_ok=True)
data_file = "data/students.json"
# Если файла нет, создаём пример данных
if not os.path.exists(data_file):
example_students = [
{"id": 1, "name": "Иван Петров", "courses": ["Математика", "Программирование на Python", "Физика"], "grades": [85, 92, 78]},
{"id": 2, "name": "Мария Сидорова", "courses": ["Программирование на Python", "Английский язык"], "grades": [95, 88, 91]},
{"id": 3, "name": "Алексей Иванов", "courses": ["Математика", "Физика"], "grades": [72, 68, 74]},
{"id": 4, "name": "Елена Смирнова", "courses": ["Программирование на Python", "Базы данных"], "grades": [100, 98, 97]},
{"id": 5, "name": "Дмитрий Козлов", "courses": ["Математика"], "grades": [60, 65]}
]
with open(data_file, 'w', encoding='utf-8') as f:
json.dump(example_students, f, indent=2, ensure_ascii=False)
print(f"Создан пример файла {data_file}")
# 1. Загрузка
print("1. Загрузка данных...")
students = load_students(data_file)
print(f"Загружено студентов: {len(students)}")
# 2. Валидация и фильтрация некорректных
print("\n2. Валидация данных...")
valid_students = []
for s in students:
if validate_student_data(s):
valid_students.append(s)
else:
print(f"Предупреждение: студент {s.get('name', '?')} (id={s.get('id')}) содержит некорректные данные и будет пропущен.")
students = valid_students
print(f"После валидации осталось: {len(students)} студентов.")
# 3. Добавление поля avg_grade
print("\n3. Вычисление среднего балла для каждого студента...")
for s in students:
s['avg_grade'] = calculate_average_grade(s['grades'])
print(f"{s['name']}: средний балл = {s['avg_grade']:.2f}")
# 4. Топ-студенты с порогом 85.0
print("\n4. Топ-студенты (средний балл >= 85.0):")
top = find_top_performers(students, 85.0)
for s in top:
print(f" {s['name']}{s['avg_grade']:.2f}")
# 5. Студенты курса "Программирование на Python"
course_name = "Программирование на Python"
print(f"\n5. Студенты, изучающие курс «{course_name}»:")
python_students = get_students_by_course(students, course_name)
for s in python_students:
print(f" {s['name']}")
# 6. Генерация и сохранение отчёта
print("\n6. Генерация отчёта...")
report = generate_report(students)
report_path = "data/report.json"
save_report(report, report_path)
print(f"Отчёт сохранён в {report_path}")
# 7. Демонстрация add_student и remove_student
print("\n7. Демонстрация add_student и remove_student:")
new_student = {"id": 99, "name": "Тест Тестов", "courses": ["Программирование на Python"], "grades": [90, 85]}
students = add_student(students, new_student)
print(f"После добавления нового студента: {len(students)} студентов.")
students = remove_student(students, 2) # удалим Марию Сидорову
print(f"После удаления студента с id=2: {len(students)} студентов.")
# Восстановим удалённого для чистоты (необязательно)
students = add_student(students, {"id": 2, "name": "Мария Сидорова", "courses": ["Программирование на Python", "Английский язык"], "grades": [95, 88, 91]})
print(f"Восстановили Марию: {len(students)} студентов.")
# 8. Сортировка по среднему баллу и вывод первых 5
print("\n8. Первые 5 студентов при сортировке по убыванию среднего балла:")
sorted_students = sort_students_by_grade(students, reverse=True)
for s in sorted_students[:5]:
print(f" {s['name']}{calculate_average_grade(s['grades']):.2f}")
print("\nРабота программы завершена.")
if __name__ == "__main__":
main()