Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Чурсин Матвей. Решение тестового задания на Java #26

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
### IntelliJ IDEA ###
out/
!**/src/main/**/out/
!**/src/test/**/out/

### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
bin/
!**/src/main/**/bin/
!**/src/test/**/bin/

### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/

### VS Code ###
.vscode/

### Mac OS ###
.DS_Store
8 changes: 8 additions & 0 deletions .idea/artifacts/shchool2024_test_task6_jar.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions .idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

97 changes: 97 additions & 0 deletions .idea/workspace.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 29 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,35 @@ a30b4d51-11b4-49b2-b356-466e92a66df7 Иванов Иван Иванович 16.0
Примеры входного и выходного файлов приложены к настоящему техническому заданию.

## Автор решения

Чурсин Матвей Александрович
## Описание реализации
Программа написана на Java jdk 17

Для выполнения требований к заданию было реализованно 5 классов:

Employee, FileHandler, EmployeeHandler, TimeAnalyzer и Main
в Main идет пошаговый вызов всех необходимых методов из других классов.

FileHandler отвечает за работу с файлами и обладает 2мя методами: readFile и writeFile. данные методы служат только для работы с файлами и никакой логики в себе не выполняют.

Employee является record, а не стандартным классом, для того, чтобы снизить объем написания стандартного кода и обеспечить иммутабельность данных, это привело к некоторым трудностям, которые были успешно решены другими способами

EmployeeHandler содержит в себе всю логику, связанную с предварительной обработкой данных перед использованием их другими классами. groupEmployees формирует из входного набора данных набор уникальных записей с проссумированным недельным временем работы
sortEmployees сортирует окончательные данные согласно заданию и подготавливает их к записи в файл, также согласно заданию. Эти 2 функции можно разнести на разные методы без проблем.

TimeAnalyzer содержит в себе бизнес-логику обработки данных для выявления отклонений по цели задания.



## Инструкция по сборке и запуску решения
Для запуска вам потребуется java 17+версии.
Чтобы запустить программу, необходимо скачать файл shchool2024-test-task6.jar , желательно в пустую папку для удобства.

ссылка для скачивания:
https://github.com/EdistuovilA/school2024-test-task6/blob/master/shchool2024-test-task6.jar

после скачивания файла в папку, необходимо поместиить в нее файл с входными данными. Можно самостоятельно подготовить выходной файл и он необязательно должен быть пустым.

далее нужно открыть в терминале текущую папку и прописать следующую команду:

java -jar shchool2024-test-task6.jar <входной файл> <выходной файл>
11 changes: 11 additions & 0 deletions shchool2024-test-task6.iml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
Binary file added shchool2024-test-task6.jar
Binary file not shown.
3 changes: 3 additions & 0 deletions src/Employee.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
public record Employee(String id, String surname, String name, String patronymic, Double workedHours) {
}
//для того, чтобы не писать большой объем стандартного кода и обеспечить иммутабельность данных было решено использовать record
47 changes: 47 additions & 0 deletions src/EmployeeHandler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import java.util.*;

public class EmployeeHandler {
public static List<Employee> groupEmployees(List<Employee> ungroupEmployees){
HashMap<String, Double> employeeHashMap = new HashMap<>();
//подсчет суммарного времени работы сотрудника в течение недели. Если запись уже есть - то идет суммирование с предыдущим значением
for (Employee employee : ungroupEmployees) {
if (!employeeHashMap.containsKey(employee.id())){
employeeHashMap.put(employee.id(),employee.workedHours());
} else {
employeeHashMap.put(employee.id(),employeeHashMap.get(employee.id())+employee.workedHours());
}
}
//формирование списка новых record employee, т.к. нельзя обновить старые.
List<Employee> groupedEmployees = new ArrayList<>();
for (Employee employee : ungroupEmployees) {
groupedEmployees.add(new Employee(employee.id(), employee.surname(), employee.name(), employee.patronymic(), employeeHashMap.get(employee.id())));
}
return groupedEmployees;
}

public static List<String> sortEmployees(HashMap<Employee, Double> unsortedMap){
List<Employee> sortedList = new ArrayList<>();
for (var entry : unsortedMap.entrySet()){
sortedList.add(entry.getKey());
}
//сортировка идет по условию задачи: приоритет имеет разница с требуемым временем, далее же идет стандартная сорировка по ФИО
sortedList.sort(Comparator.comparingDouble( (Employee emp) -> unsortedMap.get(emp))
.thenComparing(Employee::surname)
.thenComparing(Employee::name)
.thenComparing(Employee::patronymic));

List<String> sortedData = new ArrayList<>();

//приведение данных к необходимому формату вывода
for (Employee employee : sortedList) {
Double disbalanceTime = unsortedMap.get(employee);
//задание формата данных для разницы времени: указание знака и отбрасывание нулей при необходимости
String timeFormat = (disbalanceTime % 1 == 0) ? "%+.0f" : "%+.2f";
sortedData.add(String.format("%s %s.%s. %s",
employee.surname(), employee.name().charAt(0),employee.patronymic().charAt(0),
String.format(Locale.ROOT, timeFormat, disbalanceTime)));
}
return sortedData;
}

}
39 changes: 39 additions & 0 deletions src/FileHandler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.stream.Stream;

public class FileHandler {

public static List<Employee> readFile(Path readPath) throws IOException {
//два набора stream необходимы, т.к. каждый из них можно использовать лишь один раз.
Stream<String> dataLines = Files.lines(readPath);
Stream<String> dataLines2 = Files.lines(readPath);
List<String> normalTimeString = dataLines2.toList();
TimeAnalyzer.timeNorm = Integer.parseInt(normalTimeString.get(0));

//преобразование данных из файла в record Employee
return dataLines.skip(1).map(
(String employeeString) -> {
String[] empData = employeeString.split(" ");
return new Employee(empData[0], empData[1], empData[2], empData[3], Double.parseDouble(empData[5]));
}).toList();

}


public static void writeFile(List<String> sortedData, String writePath){
try (BufferedWriter writer = new BufferedWriter (new FileWriter(writePath))){
for (String data:sortedData) {
writer.write(data);
writer.append('\n');
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}

}
3 changes: 3 additions & 0 deletions src/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Manifest-Version: 1.0
Main-Class: Main

20 changes: 20 additions & 0 deletions src/Main.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import java.io.IOException;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.List;

public class Main {

public static void main(String[] args) throws IOException {
//чтение данных из файла
List<Employee> employees = FileHandler.readFile(Path.of(args[0]));
//получение из всех данных сгруппированный по id набор, где каждая запись уникальна, а рабочее время сложено из всех повторений
employees = EmployeeHandler.groupEmployees(employees);
//получение из данных пары работник - его отклонение от нормы
HashMap<Employee,Double> employeeDoubleHashMap = TimeAnalyzer.disbalanceAnalyzer(employees);
//сортировка работников по условиям задания и преобразование их к данным на вывод
List<String> outputData = EmployeeHandler.sortEmployees(employeeDoubleHashMap);
//запись данных в файл
FileHandler.writeFile(outputData, args[1]);
}
}
19 changes: 19 additions & 0 deletions src/TimeAnalyzer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import java.util.HashMap;
import java.util.List;

public class TimeAnalyzer {
static int timeNorm; //норма времени из первой строки файла
private static final double disbalanceLimit = 0.1; //максимально допустимое процентное значение отклонения, жестко указано в задании

public static HashMap<Employee, Double> disbalanceAnalyzer(List<Employee> employees){
double limitHoursOfDisbalance = timeNorm * disbalanceLimit; //максимально допустимое значение (в часах)
HashMap <Employee, Double> disbalanceEmployees = new HashMap<>();
for (Employee employee: employees) {
double disbalance = employee.workedHours() - timeNorm;
if (Math.abs(disbalance) > limitHoursOfDisbalance){
disbalanceEmployees.put(employee,disbalance);
}
}
return disbalanceEmployees;
}
}