Посчитать общую зарплату уникальных руководителей сотрудников старше 40 лет

20. Посчитать общую зарплату уникальных руководителей сотрудников старше 40 лет

Условие задачи:

Дан список сотрудников employees.

Каждый сотрудник содержит:

  • имя;

  • возраст;

  • зарплату;

  • множество руководителей heads.

Необходимо найти общую зарплату всех руководителей сотрудников, возраст которых больше 40 лет.

Один и тот же руководитель может быть указан у нескольких сотрудников. В таком случае его зарплата должна учитываться только один раз.

Код:

@Data
class User {

    private String name;
    private int age;
    private double salary;
    private Set<User> heads;
}

List<User> employees = ...;

Спойлеры к решению

Подсказки

💡 Сначала необходимо оставить только сотрудников старше 40 лет.

💡 У каждого сотрудника находится коллекция heads, поэтому для получения одного общего потока руководителей можно использовать flatMap().

💡 Один руководитель может встречаться у нескольких сотрудников. Перед суммированием необходимо удалить дубликаты.

💡 Для получения общей зарплаты удобно преобразовать поток в DoubleStream с помощью mapToDouble().


Решение

Сначала отфильтруем сотрудников по возрасту:

.filter(employee -> employee.getAge() > 40)

После этого получим всех их руководителей.

Поскольку getHeads() возвращает Set<User>, для объединения руководителей всех сотрудников в один поток используем flatMap():

.flatMap(employee -> employee.getHeads().stream())

Один и тот же руководитель может присутствовать у нескольких сотрудников, поэтому используем distinct().

Итоговое решение:

double totalSalary = employees.stream()
        .filter(employee -> employee.getAge() > 40)
        .flatMap(employee -> employee.getHeads().stream())
        .distinct()
        .mapToDouble(User::getSalary)
        .sum();

Полный пример:

import lombok.Data;

import java.util.List;
import java.util.Set;

public class Main {

    public static void main(String[] args) {

        List<User> employees = ...;

        double totalSalary = employees.stream()
                .filter(employee -> employee.getAge() > 40)
                .flatMap(employee -> employee.getHeads().stream())
                .distinct()
                .mapToDouble(User::getSalary)
                .sum();

        System.out.println(totalSalary);
    }
}

@Data
class User {

    private String name;
    private int age;
    private double salary;
    private Set<User> heads;
}

Разберём pipeline:

employees
filter(age > 40)
получаем heads каждого сотрудника
flatMap()
единый поток руководителей
distinct()
уникальные руководители
mapToDouble(User::getSalary)
sum()

Например, если есть сотрудники:

Employee 1, age = 45 → heads: [Head A, Head B]
Employee 2, age = 50 → heads: [Head A, Head C]

а зарплаты руководителей:

Head A → 100 000
Head B → 150 000
Head C → 200 000

то Head A встречается два раза, но его зарплата должна учитываться только один раз.

Результат:

100 000 + 150 000 + 200 000 = 450 000

Важный момент с distinct() #

Метод:

distinct()

определяет уникальность объектов через equals() и hashCode().

Поскольку используется Lombok-аннотация:

@Data

Lombok генерирует equals() и hashCode() автоматически.

Однако в реальном приложении стоит внимательно определить, по каким полям два пользователя считаются одним и тем же человеком. Обычно для этого лучше использовать уникальный идентификатор пользователя, а не все поля объекта.

Сложность #

При условии корректной реализации hashCode():

  • время — примерно O(n + h), где n — количество сотрудников, а h — общее количество рассматриваемых руководителей;

  • дополнительная память — O(k), где k — количество уникальных руководителей, которое необходимо хранить для работы distinct().