Как реализовать группировку и расчет среднего на основании информации из HashSet?

231
25 августа 2021, 13:00

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

Использую коллекцию Set<Employee> employeeList;

Класс Employee имеет поля:

private long id;
private String fullName;
private Department department; (enum)
private BigDecimal salary;

Пытался сгруппировать таким образом, чтобы вывести список подразделений и среднюю зарплату, но в моем случае salary типа BigDecimal и метод averaging не подходит, т.к. он работает с int, double, long, а я пытаюсь найти среднее типа BigDecimal. Наверное такой подход реализовать до конца нет возможности? Тут либо вместо BigDecimal использовать другой тип или другим путем реализовывать метод. Как пытался делать:

public List<Employee> averageSalaryReport() {
    Map<Department, BigDecimal> averageSalaryDepartment = employeeList.stream()
    .collect(groupingBy(Employee::getDepartment,averagingInt(Employee::getSalary)));
    ...
}

P.s. Надеюсь, что более-менее понятно описал суть. Новичок в этом деле. Буду очень благодарен за помощь!

Answer 1

Вместо averagingInt реализуйте свой Collector, только для BigDecimal. Реализацию averagingInt посмотреть легко, возьмите её за основу:

public static void main(String[] args) throws Exception {
    List<Employee> employees = Arrays.asList(
            new Employee(1, "vasya", Department.ONE, BigDecimal.valueOf(100)),
            new Employee(2, "fedya", Department.TWO, BigDecimal.valueOf(300)),
            new Employee(3, "cj", Department.MAIN, BigDecimal.valueOf(1100)),
            new Employee(4, "madonna", Department.TWO, BigDecimal.valueOf(500)),
            new Employee(5, "tatyana", Department.MAIN, BigDecimal.valueOf(200)),
            new Employee(6, "michael jackson", Department.ONE, BigDecimal.valueOf(500)),
            new Employee(7, "petro", Department.ONE, BigDecimal.valueOf(300))
    );
    Map<Department, BigDecimal> averageSalaryDepartment =
            averageSalaryReport(employees);
    System.out.println(averageSalaryDepartment);
}
public static Map<Department, BigDecimal> averageSalaryReport(List<Employee> employeeList) {
     return employeeList.stream()
            .collect(groupingBy(Employee::getDepartment,
                Collector.of(() -> new BigDecimal[]{BigDecimal.ZERO, BigDecimal.ZERO},
                            (a, t) -> { a[0] = a[0].add(t.getSalary()); a[1] = a[1].add(BigDecimal.ONE); },
                            (a, b) -> { a[0] = a[0].add(b[0]); a[1] = a[1].add(b[1]); return a; },
                            a -> (a[1].compareTo(BigDecimal.ZERO) == 0) ? BigDecimal.ZERO : a[0].divide(a[1], BigDecimal.ROUND_HALF_UP))));
}
Answer 2

Получилось как-то так ( без создания своего коллектора):

employeeList.stream()
        .collect(Collectors.groupingBy(
                Employee::getDepartment,
                Collectors.mapping(Employee::getSalary, Collectors.toList())
        ))
        .forEach((key, list) -> {
            final BigDecimal total = list.stream()
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal average = total.divide(BigDecimal.valueOf(list.size()));
            averageMap.put(key, average);
        });
READ ALSO
Некоторые странные моменты связанные с потребностью сделать Нисходящее Приведение (Java)

Некоторые странные моменты связанные с потребностью сделать Нисходящее Приведение (Java)

Мой вопрос написал ниже в комментах программы с достаточно подробным описанием причины возникновения собственно самого вопроса

201
Сравнение символов в массивах

Сравнение символов в массивах

корректно будет использовать оператор "==" для сравнения двух символов из двух массивов? Не адреса в памята а именно совпадение знаков(если...

126
Не заходит в метод с аннотацией @PostConstruct (javax)

Не заходит в метод с аннотацией @PostConstruct (javax)

Можно ли вызвать определенный метод инициализация сразу после вызова конструктора с помощью аннотаций из javax?

83
Как отключить фоновый процесс?

Как отключить фоновый процесс?

Я делаю приложение на CordovaСтояла задача: создать плагин, который бы создавал фоновый процесс, который в свою очередь каждые 30 секунд отправлял...

281