261 lines
12 KiB
Python
261 lines
12 KiB
Python
# 1. Читает текстовый файл с данными (каждая строка: имя,отдел,зарплата,стаж).
|
||
# Возвращает список словарей: [{"name": str, "dept": str, "salary": float, "exp": float}, ...].
|
||
|
||
|
||
def load_data(filepath: str) -> list[dict]:
|
||
employees = []
|
||
#filepath = "data/employees.txt"
|
||
try:
|
||
with open(filepath, "r", encoding="utf-8") as file:
|
||
for line_number, line in enumerate(file, 1):
|
||
# Чищу строку от пробелов по краям и скипаю пустые строки, а то хз кто там этот емплоес.тииксти писал
|
||
line = line.strip()
|
||
if not line:
|
||
continue
|
||
|
||
try:
|
||
# делим строку по запятой
|
||
parts = [p.strip() for p in line.split(",")] # зачем нейронки если всю эту строку мне пайчарм вставил после знака равно???
|
||
|
||
if len(parts) != 4: # ну вдруг там не 4 колонки
|
||
print(f"Ошибка в строке {line_number}: надо 4 значения, а получил {len(parts)}.")
|
||
continue
|
||
|
||
employee = {
|
||
"name": parts[0],
|
||
"dept": parts[1],
|
||
"salary": float(parts[2]),
|
||
"exp": float(parts[3])
|
||
}
|
||
employees.append(employee)
|
||
|
||
except ValueError as e:
|
||
print(f"Ошибка преобразования типов в строке {line_number}: {e}")
|
||
|
||
except FileNotFoundError:
|
||
print(f"Ошибка: Файл по адресу '{filepath}' не найден.")
|
||
except Exception as e:
|
||
print(f"Произошла непредвиденная ошибка: {e}")
|
||
|
||
return employees
|
||
|
||
|
||
|
||
# 2. Возвращает новый список, содержащий только сотрудников указанного отдела.
|
||
def filter_by_department(employees: list[dict], department: str) -> list[dict]:
|
||
filtered_list = []
|
||
|
||
if not isinstance(employees, list):
|
||
print("Ошибка: на вход филтру должен подаваться только список")
|
||
return []
|
||
|
||
for emp in employees: # По каждому сотруднику в исходном списке
|
||
# чекаем совпадает ли отдел, убираем пробелы и приводим к одному регистру на всякий пожарный
|
||
if emp.get ('dept', '').strip().lower() == department.strip().lower():
|
||
filtered_list.append(emp)
|
||
|
||
return filtered_list
|
||
|
||
|
||
|
||
# 3. Возвращает новый список с сотрудниками, чей стаж (exp) не меньше min_years.
|
||
def filter_by_experience(employees: list[dict], min_years: float) -> list[dict]:
|
||
experienced_staff = []
|
||
|
||
# вдруг там не список
|
||
if not isinstance(employees, list):
|
||
print("Ошибка: На вход ожидался список сотрудников.")
|
||
return []
|
||
|
||
for emp in employees:
|
||
try:
|
||
# вытаскиваем стаж и смотрим чтоб не меньше мин ерс
|
||
if emp.get('exp', 0) >= min_years:
|
||
experienced_staff.append(emp)
|
||
|
||
except TypeError: # Если в ехр лежит не число
|
||
print(f"Ошибка: Некорректный формат стажа у сотрудника {emp.get('name')}")
|
||
continue
|
||
return experienced_staff
|
||
|
||
|
||
|
||
# 4. Вычисляет среднюю зарплату по переданному списку сотрудников. Если список пуст, возвращает 0.0.
|
||
def calculate_average_salary(employees: list[dict]) -> float:
|
||
# проверяем пустой ли список
|
||
if not employees:
|
||
return 0.0
|
||
|
||
total_sum = 0.0
|
||
|
||
# Сумируем зарплату каждого сотрудника
|
||
for emp in employees:
|
||
total_sum += emp.get('salary', 0.0) # get чтоб не упасть если ключа нет
|
||
|
||
average = total_sum / len(employees)
|
||
return float(average)
|
||
|
||
# 5. Возвращает словарь сотрудника с максимальной зарплатой. При пустом списке возвращает None.
|
||
def find_highest_paid(employees: list[dict]) -> dict | None:
|
||
if not employees:
|
||
return None
|
||
|
||
highest_paid_emp = employees[0]
|
||
|
||
for emp in employees:
|
||
if emp.get("salary", 0) > highest_paid_emp.get('salary', 0):
|
||
highest_paid_emp = emp
|
||
return highest_paid_emp
|
||
|
||
|
||
|
||
# 6. Группирует сотрудников по отделам. Возвращает словарь, где ключ – название отдела,
|
||
# значение – список сотрудников этого отдела.
|
||
def group_by_department(employees: list[dict]) -> dict[str, list[dict]]:
|
||
departments = {}
|
||
|
||
for emp in employees:
|
||
dept_name = emp.get('dept', 'Unknown')
|
||
|
||
# если такого отдела нет, создаём для него пустой список
|
||
if dept_name not in departments:
|
||
departments[dept_name] = []
|
||
|
||
departments[dept_name].append(emp) # добавляем текущего сотрудника в список его отдела
|
||
return departments
|
||
|
||
|
||
|
||
# 7. Увеличивает значение salary каждого сотрудника в переданном списке на bonus_percent процентов.
|
||
# Изменяет исходные словари (модификация на месте). Функция ничего не возвращает.
|
||
def add_bonus(employees: list[dict], bonus_percent: float) -> None:
|
||
# в кефах удобнее
|
||
multiplier = 1 + (bonus_percent / 100)
|
||
|
||
for emp in employees:
|
||
if "salary" in emp:
|
||
emp["salary"] = round(emp["salary"] * multiplier, 2) # раунд тут если чё чтоб не вылезло чудо по типу 0.0000001
|
||
|
||
|
||
# 8. Принимает словарь одного сотрудника, возвращает отформатированную строку:
|
||
# "Имя: {name}, Отдел: {dept}, Зарплата: {salary:.2f} руб., Стаж: {exp} лет".
|
||
def format_employee_string(employee: dict) -> str:
|
||
formatted_str = (
|
||
f"Имя: {employee.get('name', 'Не указано')}, "
|
||
f"Отдел: {employee.get('dept', 'Не указано')}, "
|
||
f"Зарплата: {employee.get('salary', 0.0):.2f} руб., "
|
||
f"Стаж: {employee.get('exp', 0)} лет"
|
||
)
|
||
|
||
return formatted_str
|
||
|
||
# 9. Возвращает новый список сотрудников, отсортированный по зарплате
|
||
# (по возрастанию, если reverse=False, иначе по убыванию).
|
||
def sort_by_salary(employees: list[dict], reverse: bool = False) -> list[dict]:
|
||
if not employees or not isinstance(employees, list): # Если пустой или ваще не список - вернём как есть
|
||
return []
|
||
|
||
sorted_list = sorted(
|
||
employees,
|
||
key=lambda emp: emp.get('salary', 0.0),
|
||
reverse=reverse
|
||
)
|
||
|
||
return sorted_list
|
||
|
||
# 10. Сохраняет в файл по пути filepath текстовый отчёт:
|
||
# для каждого сотрудника – строка, полученная функцией format_employee_string().
|
||
# Если список пуст, записывает строку "Нет данных".
|
||
def save_report(employees: list[dict], filepath: str) -> None:
|
||
try:
|
||
with open(filepath, "w", encoding="utf-8") as file:
|
||
# 1. Если список пуст, пишем "Нет данных"
|
||
if not employees:
|
||
file.write("Нет данных\n")
|
||
else:
|
||
# 2. Проходим по каждому сотруднику
|
||
for emp in employees:
|
||
# Используем твою функцию форматирования
|
||
line = format_employee_string(emp)
|
||
# Записываем строку и добавляем перенос на новую строку
|
||
file.write(line + "\n")
|
||
print(f"Отчет успешно сохранен в файл: {filepath}")
|
||
|
||
except Exception as e:
|
||
print(f"Ошибка при сохранении файла: {e}")
|
||
|
||
|
||
def main():
|
||
# Главная функция, демонстрирующая работу всех функций обработки данных сотрудников
|
||
|
||
print("=" * 37)
|
||
print("ОБРАБОТКА ДАННЫХ СОТРУДНИКОВ КОМПАНИИ")
|
||
print("=" * 37)
|
||
|
||
# 1. Загружаем данные из файла
|
||
filepath = "data/employees.txt"
|
||
print(f"\n1. Загрузка данных из файла '{filepath}'...")
|
||
employees = load_data(filepath)
|
||
print(f" Загружено сотрудников: {len(employees)}")
|
||
for emp in employees:
|
||
print(f" - {emp['name']}, отдел: {emp['dept']}")
|
||
|
||
# 2. Демонстрация filter_by_experience - сотрудники со стажем >= 5 лет
|
||
print("\n2. Сотрудники со стажем >= 5 лет:")
|
||
experienced = filter_by_experience(employees, 5.0)
|
||
if experienced:
|
||
for emp in experienced:
|
||
print(f" - {emp['name']} (стаж: {emp['exp']} лет)")
|
||
else:
|
||
print(" Нет сотрудников с таким стажем.")
|
||
|
||
# 3. Фильтруем сотрудников отдела Sales
|
||
print("\n3. Фильтрация сотрудников отдела 'Sales'...")
|
||
sales_employees = filter_by_department(employees, "Sales")
|
||
print(f" Найдено сотрудников в отделе Sales: {len(sales_employees)}")
|
||
|
||
# 4. Назначаем бонус 10% сотрудникам отдела Sales
|
||
print("\n4. Начисление бонуса 10% сотрудникам отдела Sales...")
|
||
add_bonus(sales_employees, 10.0)
|
||
print(" Бонус начислен. Зарплаты после бонуса:")
|
||
for emp in sales_employees:
|
||
print(f" - {emp['name']}: {emp['salary']:.2f} руб.")
|
||
|
||
# 5. Сортируем сотрудников Sales по убыванию зарплаты
|
||
print("\n5. Сортировка сотрудников Sales по убыванию зарплаты...")
|
||
sorted_sales = sort_by_salary(sales_employees, reverse=True)
|
||
print(" Отсортированный список:")
|
||
for emp in sorted_sales:
|
||
print(f" - {emp['name']}: {emp['salary']:.2f} руб.")
|
||
|
||
# 6. Вычисляем среднюю зарплату после бонуса
|
||
print("\n6. Средняя зарплата в отделе Sales после бонуса:")
|
||
avg_salary = calculate_average_salary(sorted_sales)
|
||
print(f" {avg_salary:.2f} руб.")
|
||
|
||
# 7. Находим сотрудника с самой высокой зарплатой
|
||
print("\n7. Сотрудник с самой высокой зарплатой в отделе Sales:")
|
||
highest_paid = find_highest_paid(sorted_sales)
|
||
if highest_paid:
|
||
print(f" {highest_paid['name']} - {highest_paid['salary']:.2f} руб.")
|
||
|
||
# 8. Группируем ВСЕХ сотрудников по отделам и выводим количество
|
||
print("\n8. Группировка всех сотрудников по отделам:")
|
||
grouped = group_by_department(employees)
|
||
for dept, staff in grouped.items():
|
||
print(f" Отдел '{dept}': {len(staff)} чел.")
|
||
for emp in staff:
|
||
print(f" - {emp['name']}")
|
||
|
||
# 9. Сохраняем итоговый отчёт по отделу Sales
|
||
print("\n9. Сохранение отчёта по отделу Sales...")
|
||
report_path = "report_sales.txt"
|
||
save_report(sorted_sales, report_path)
|
||
|
||
print("\n" + "=" * 60)
|
||
print("ОБРАБОТКА ЗАВЕРШЕНА")
|
||
print("=" * 60)
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main() |