Расчёт средней заработной платы с помощью стримов
Задача: расчёт средней заработной платы отделов с помощью стримов
public class Task implements AutoCloseable {
public static List<Double> avgEmp = new ArrayList<>();
public static void main(String[] args) throws IOException {
Map<String, Department> departments = new HashMap<>();
String path = args.length > 0 ? args[0] : null;
assert path != null;
try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(path), "CP1251")); br) {
String line; // Как мне объявить line в while
while ((line = br.readLine()) != null) {
if (check(line)) {
String[] strings = line.split("/");
Employee emp = new Employee(strings[0], new Double(strings[1]));
if (!departments.containsKey(strings[2])) {
departments.put(strings[2], new Department(strings[2]));
}
departments.get(strings[2]).addEmployee(emp);
System.out.println(strings[0] + " " + strings[1] + " " + strings[2] + " - корректна, обрабатываем");
}
}
systemMessage(0);
avg(departments);
} catch (FileNotFoundException e) {
System.out.println("Файл не был найден, проверьте путь");
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Исправьте путь к файлу, выходите за массив");
} catch (NullPointerException e) {
System.out.println("Вы забыли прописать путь к файлу");
} finally {
System.out.println("Читаемый файл закрыт");
}
}
public static boolean check(String line) {
String regex = "[А-Яа-яЁёA-Za-z\\s]+";
if (!(line = line.trim()).isEmpty()) {
String[] strings = line.split("/");
if (strings.length < 3) {
System.out.println(line + " - неверный формат строки, ожидаем ФИО/10000.12/Департамент");
return false;
}
if (!(strings[0].matches(regex) && strings[2].matches(regex))) {
System.out.println(line + " - неверный формат ввода, нужно: Буквы/Цифры/Буквы");
return false;
}
if (!strings[1].matches("\\d{5}(\\.\\d{1,2})?")) {
System.out.println(line + " - некорректный ввод цифр, знаков. Зарплата не может быть отрицательной и иметь меньше 5 знаков");
return false;
}
return true;
}
return false;
}
public static void avg(Map<String, Department> departments) {
for (Department dep : departments.values()) {
Double avg = dep.salaryAvg();
avgEmp.add(avg);
System.out.println("Средняя заработная плата отдела " + dep.getName () + ": " + avg);
}
}
Ответы (1 шт):
Слишком сложная реализация.
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@lombok.Data
@lombok.AllArgsConstructor
public class Employee implements Comparable<Employee>{
private final String name;
private final Double salary;
private final String departmentName;
public static Map<String, Queue<Employee>> fromFile(String fileName, String separator) throws IOException {
try (Stream<String> stream = Files.lines(Paths.get(fileName))) {
return stream
.map(line -> line.split(separator))
.map(args->Employee.of(args))
.filter(employee->employee!=null)
.collect(Collectors.groupingBy(Employee::getDepartmentName, HashMap::new,
Collectors.toCollection(PriorityQueue::new)));
}
}
private static Employee of(String[] args) {
try {
return new Employee(args[0].trim(), Double.valueOf(args[1].trim()), args[2].trim());
} catch (NumberFormatException | NullPointerException | ArrayIndexOutOfBoundsException e) {
return null;
}
}
@Override
public int compareTo(Employee employee) {
return this.salary.compareTo(employee.salary);
}
}
import java.io.IOException;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Queue;
import java.util.stream.Collectors;
import org.springframework.data.util.Pair;
public class Task {
public static void main(String[] args) throws IOException {
Map<String, Queue<Employee>> employes = Employee.fromFile("1.txt", "/");
Map<String, Double> salaryAvg =
employes.entrySet().stream()
.map(e->Pair.of(e.getKey(), e.getValue().stream().mapToDouble(Employee::getSalary).average().getAsDouble()))
.sorted(Comparator.comparingDouble(Pair::getSecond))
.collect(Collectors.toMap(Pair::getFirst, Pair::getSecond, (o1, o2) -> o1, LinkedHashMap::new));
System.out.println(salaryAvg);
//todo
}
}
Сделайте класс сотрудников немного "умнее". Пусть он сам себя парсит. Тогда из класса Task просто вызывайте метод класса сотрудников для того, чтобы преобразовать текстовый файл в коллекцию типа Map, при этом в аргументах передается имя файла и разделитель, но поскольку используется split разделителем может быть и регулярка для более сложных случаев.
Из метода вы получите практически такую же Map, только ее значение будет типизировано очередью с приоритетом, а не листом. Для этого типа коллекции можно задать компаратор и получить элементы при переборе в нужном порядке (так мы упорядочим сотрудников по наростанию зп).
Получив такую коллекцию мы можем посчитать среднюю зп для всех отделов, которые также положим в коллекцию типа ключ-значение, где ключ - имя отдела, значение - средняя зп, причем эта коллекция также сортирована по возростанию зп.
Дальше дело техники. Вы имеете две упорядоченные коллекции : имя отдела - список сотрудников в порядке возрастания зп и имя отдела - средняя зп в отделе по возрастанию. В комментариях вам подсказали алгоритм. У очереди есть удобные инструменты для получения с удалением и пр., чего нет в листе. Класса департамент больше нет, поэтому будет достаточно изменить его имя в самом классе работника и добавить в Map по ключу нового отдела.
Я использую lombok (которую вы также можете подключить) и класс Pair и спринга (он есть также в апачевских утилитах), но можете обойтись и без него.