Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java 8 lambda for selecting top salary employee for each department

class Employee {
    public string department;
    public int salary;
}

List<Employee> allEmployees = ...

I need to have a list that will have only 1 top salary employee for each department. allEmployees is the source list.

like image 609
Yuriy Avatar asked Mar 16 '16 16:03

Yuriy


3 Answers

You can do that with a grouping collector:

Map<String, Employee> topEmployees =
    allEmployees.stream()
                .collect(groupingBy(
                    e -> e.department,
                    collectingAndThen(maxBy(comparingInt(e -> e.salary)), Optional::get) 
                ));

with the static imports

import static java.util.Comparator.comparingInt;
import static java.util.stream.Collectors.collectingAndThen;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.maxBy;

This code creates a Stream of all the employees and groups them with their department with the help of Collectors.groupingBy. For all the values classified to the same key, we need to keep only the employee with the maximum salary, so we collect them with Collectors.maxBy and the comparator compares the salary with Comparator.comparingInt. Since maxBy returns an Optional<Employee> (to handle the case where there the list is empty), we wrap it with a call to Collectors.collectingAndThen with a finisher that just returns the employee: we know in this case that the optional won't be empty.

like image 57
Tunaki Avatar answered Oct 23 '22 01:10

Tunaki


Alternative solution:

Map<String, Employee> topEmployees =
    allEmployees.stream()
            .collect(Collectors.toMap(
                e -> e.department,
                e -> e,
                BinaryOperator.maxBy(Comparator.comparingInt(e -> e.salary)) 
            ));

When we encounter the first employee from the department, we add a new entry to the Map. When another employee is found, one with higher salary is kept. This way you don't need to meddle with optionals.

like image 27
Tagir Valeev Avatar answered Oct 23 '22 01:10

Tagir Valeev


/Let's say you have a list of employee as List employeeList; To find the departmentwise salary first you need to have comparator for employees/

Comparator<Employee> bySalary = Comparator.comparing(Employee::getSalary);

Then to find departement wise highest salary you do

Map<String, Optional<Employee>> collect = 
        employeeList.stream().collect(
            Collectors.groupingBy(
                Employee::getDept,
                Collectors.reducing(BinaryOperator.maxBy(bySalary))
    )
);

What are we doing here is, we are grouping the employees on the basis of there department. And along with Grouping we are saying return me the highest salary taker for that department, And finally pick only max one. To see the output override toString method in Employee class and do */

collect.entrySet().stream().forEach(System.out::println);
like image 3
Vaibhav Avatar answered Oct 23 '22 01:10

Vaibhav