How to rewrite the ValueMapper Function using java lambda

secret super star :

Is it possible/correct(to) or rewrite the below below using lambda? Here I have provided inline implementations for KeyMapper and ValueMapper Function.

public Map<Integer, List<Employee>> getSubordinateHighestSalEmpMapV1(List<Employee> employees) {

        return employees.stream()
        .filter(e -> e.getSubordinates() != null)
        .collect(Collectors.toMap( //keyMapper
         new Function<Employee, Integer>() {

            @Override
            public Integer apply(Employee t) {
                return t.getId();
            }
        }, 
        new Function<Employee, List<Employee>>() {//valueMapper

            @Override
            public List<Employee> apply(Employee t) {
                List<Employee> subordinates = t.getSubordinates();
                List<Employee> subOrdinatesListWithHighestSalary = new ArrayList<>();
                int maxSal = Integer.MIN_VALUE;
                for(Employee s: subordinates) {
                    if(s.getSalary() >= maxSal) {
                        maxSal = s.getSalary();
                    }
                }
                for(Employee s: subordinates) {
                    if(s.getSalary() == maxSal) {
                        subOrdinatesListWithHighestSalary.add(s);
                    }
                }
                return subOrdinatesListWithHighestSalary;
            }
        }));
    }

What am I try to achieve:

The employee class is having List<Employee> subordinates. I am trying to get highest salary paid among the subordinates under each employee. each employee may or may not have subordinates. If subordinates are not present they are not included in result. If more than one subordinate having same highest salary, all of them should be present in result.

For example, it is similar to get highest paid employee(employees, if salaries match) in each department.

Employee.java

import java.util.List;

public class Employee{

    private int id;
    private int salary;
    private List<Employee> subordinates;
    private String name;
    private int age;

    public int getId() {
        return id;
    }
    public Employee setId(int id) {
        this.id = id;
        return this;
    }
    public int getSalary() {
        return salary;
    }
    public Employee setSalary(int salary) {
        this.salary = salary;
        return this;
    }
    public List<Employee> getSubordinates() {
        return subordinates;

    }
    public Employee setSubordinates(List<Employee> subordinates) {
        this.subordinates = subordinates;
        return this;
    }
    public String getName() {
        return name;
    }
    public Employee setName(String name) {
        this.name = name;
        return this;
    }
    public int getAge() {
        return age;
    }
    public Employee setAge(int age) {
        this.age = age;
        return this;
    }
    @Override
    public String toString() {
        return "Employee [id=" + id + ", salary=" + salary  + ", name=" + name
                + ", age=" + age + "]";
    }
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + id;
        return result;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Employee other = (Employee) obj;
        if (id != other.id)
            return false;
        return true;
    }
}

For example for below input:

  • employee1(id:100) has got employee2,employee3,employee4 and among this employee3 paid highest with 30000 and should be part of output
  • employee2(id:101) has got employee5, employee6 and among this, employee5 is highest paid with 20000 and should be part of output
  • employee3(id:102) has got employee7 and employee8 and both are paid with same salary of 16000 and output should contain both.
  • employee8(id:107) has got one subordinate employee9 with salary 12000 and employee9 should be part of output

    The below is input as explained above:

     private static List<Employee>  getEmployeeListV1() {
        int i = 100;
        Employee employee1 = (Employee) new Employee().setId(i++).setSalary(10000).setAge(101).setName("emp 1");
        Employee employee2 = (Employee) new Employee().setId(i++).setSalary(20000).setAge(110).setName("emp 2");
        Employee employee3 = (Employee) new Employee().setId(i++).setSalary(30000).setAge(20).setName("emp 3");
        Employee employee4 = (Employee) new Employee().setId(i++).setSalary(10000).setAge(32).setName("emp 4");
        Employee employee5 = (Employee) new Employee().setId(i++).setSalary(20000).setAge(34).setName("emp 5");
        Employee employee6 = (Employee) new Employee().setId(i++).setSalary(15000).setAge(44).setName("emp 6");
        Employee employee7 = (Employee) new Employee().setId(i++).setSalary(16000).setAge(56).setName("emp 7");
        Employee employee8 = (Employee) new Employee().setId(i++).setSalary(16000).setAge(65).setName("emp 8");
        Employee employee9 = (Employee) new Employee().setId(i++).setSalary(12000).setAge(74).setName("emp 9");
    
        employee1.setSubordinates(Stream.of(employee2,employee3,employee4).collect(Collectors.toList()));
        employee2.setSubordinates(Stream.of(employee5,employee6).collect(Collectors.toList()));
        employee3.setSubordinates(Stream.of(employee7,employee8).collect(Collectors.toList()));
        employee8.setSubordinates(Stream.of(employee9).collect(Collectors.toList()));
    
        List<Employee> employees = Stream.of(employee1,employee2,
                employee3,employee4,employee5,
                employee6,employee7,employee8,
                employee9).collect(Collectors.toList());
        return employees;
    
    }
    

The below is output:

100=[Employee [id=102, salary=30000, name=emp 3, age=20]]
101=[Employee [id=104, salary=20000, name=emp 5, age=34]]
102=[Employee [id=106, salary=16000, name=emp 7, age=56], Employee [id=107, salary=16000, name=emp 8, age=65]]
107=[Employee [id=108, salary=12000, name=emp 9, age=74]]

Explaination:

Ousmane D. :

Sure, you can change the keyMapper with a method reference (Employee::getId or a lambda employee -> employee.getId()) and the valueMapper (t -> { ... ) to a lambda as follows:

return employees.stream()
                .filter(e -> e.getSubordinates() != null)
                .collect(Collectors.toMap( //keyMapper
                        Employee::getId,
                        t -> {
                            List<Employee> subordinates = t.getSubordinates();
                            List<Employee> subOrdinatesListWithHighestSalary = new ArrayList<>();
                            int maxSal = Integer.MIN_VALUE;
                            for(Employee s: subordinates) {
                                if(s.getSalary() >= maxSal) {
                                    maxSal = s.getSalary();
                                }
                            }
                            for(Employee s: subordinates) {
                                if(s.getSalary() == maxSal) {
                                    subOrdinatesListWithHighestSalary.add(s);
                                }
                            }
                            return subOrdinatesListWithHighestSalary;
                        }));

You can go further and simplify the method to:

return employees.stream()
         .filter(e -> e.getSubordinates() != null)
         .collect(Collectors.toMap(Employee::getId,
                        t -> {
                            int maxSal = t.getSubordinates().stream().mapToInt(Employee::getSalary).max().orElse(Integer.MIN_VALUE);
                            return t.getSubordinates().stream().filter(x -> x.getSalary() == maxSal).collect(toCollection(ArrayList::new));

                        }));

and even further to:

return employees.stream()
                .filter(e -> e.getSubordinates() != null)
                .collect(Collectors.toMap(Employee::getId, Main::apply));

Given you have this method:

static List<Employee> apply(Employee t) {
        List<Employee> subordinates = t.getSubordinates();
        int maxSal = subordinates.stream().mapToInt(Employee::getSalary).max().orElse(Integer.MIN_VALUE);
        return subordinates.stream().filter(x -> x.getSalary() == maxSal).collect(toCollection(ArrayList::new));
}

Where Main refers to the class contain the apply helper method.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=88819&siteId=1