import json import os from typing import Optional def load_workouts(file_path: str) -> list: try: with open(file_path, 'r', encoding='utf-8') as file: workouts = json.load(file) return workouts if isinstance(workouts, list) else [] except (FileNotFoundError, json.JSONDecodeError, IOError): return [] def filter_by_type(workouts: list, workout_type: str) -> list: return [w for w in workouts if w.get('type') == workout_type] def filter_by_date_range(workouts: list, start_date: str, end_date: str) -> list: return [w for w in workouts if start_date <= w.get('date', '') <= end_date] def total_calories(workouts: list) -> int: return sum(w.get('calories', 0) for w in workouts) def average_duration(workouts: list) -> float: if not workouts: return 0.0 total_duration = sum(w.get('duration_min', 0) for w in workouts) return total_duration / len(workouts) def best_distance(workouts: list) -> Optional[dict]: distance_workouts = [w for w in workouts if w.get('distance_km', 0) > 0] if not distance_workouts: return None best = max(distance_workouts, key=lambda x: x.get('distance_km', 0)) return { 'date': best.get('date'), 'type': best.get('type'), 'distance_km': best.get('distance_km') } def calories_per_minute(workout: dict) -> float: duration = workout.get('duration_min', 0) calories = workout.get('calories', 0) if duration == 0: return 0.0 return calories / duration def add_workout(workouts: list, date: str, workout_type: str, duration_min: int, distance_km: float, calories: int, avg_heart_rate: int = None) -> list: valid_types = ['running', 'swimming', 'cycling', 'strength'] if workout_type not in valid_types: raise ValueError(f"Неверный тип тренировки. Допустимые: {valid_types}") if duration_min <= 0: raise ValueError("Длительность должна быть больше 0") if calories <= 0: raise ValueError("Калории должны быть больше 0") if distance_km < 0: raise ValueError("Дистанция не может быть отрицательной") workout = { 'date': date, 'type': workout_type, 'duration_min': duration_min, 'distance_km': distance_km, 'calories': calories } if avg_heart_rate is not None: workout['avg_heart_rate'] = avg_heart_rate workouts.append(workout) return workouts def get_heart_rate_zones(workouts: list) -> dict: zones = { 'low': 0, 'moderate': 0, 'high': 0 } for workout in workouts: heart_rate = workout.get('avg_heart_rate') if heart_rate is not None: if heart_rate < 120: zones['low'] += 1 elif heart_rate <= 150: zones['moderate'] += 1 else: zones['high'] += 1 return zones def generate_monthly_report(workouts: list, year: int, month: int) -> dict: month_workouts = [] for w in workouts: date = w.get('date', '') if date and date.startswith(f"{year}-{month:02d}"): month_workouts.append(w) if not month_workouts: return { 'total_workouts': 0, 'total_calories': 0, 'total_distance_km': 0.0, 'avg_duration_min': 0.0, 'workouts_by_type': {}, 'most_frequent_type': '' } total_workouts = len(month_workouts) total_calories = sum(w.get('calories', 0) for w in month_workouts) distance_types = ['running', 'swimming', 'cycling'] total_distance = sum(w.get('distance_km', 0) for w in month_workouts if w.get('type') in distance_types) avg_duration = sum(w.get('duration_min', 0) for w in month_workouts) / total_workouts workouts_by_type = {} for w in month_workouts: w_type = w.get('type') workouts_by_type[w_type] = workouts_by_type.get(w_type, 0) + 1 if workouts_by_type: max_count = max(workouts_by_type.values()) most_frequent = [t for t, c in workouts_by_type.items() if c == max_count] most_frequent_type = sorted(most_frequent)[0] else: most_frequent_type = '' return { 'total_workouts': total_workouts, 'total_calories': total_calories, 'total_distance_km': round(total_distance, 2), 'avg_duration_min': round(avg_duration, 1), 'workouts_by_type': workouts_by_type, 'most_frequent_type': most_frequent_type }