Как переписать функцию ValueMapper с помощью Java лямбда - PullRequest
0 голосов
/ 02 декабря 2018

Можно / исправить (переписать) или переписать нижеприведенное ниже, используя lambda?Здесь я предоставил встроенные реализации для KeyMapper и 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;
            }
        }));
    }

Чего я пытаюсь достичь:

Класс сотрудника имеет List<Employee> subordinates,Я пытаюсь получить самую высокую зарплату среди подчиненных по каждому сотруднику.каждый сотрудник может иметь или не иметь подчиненных.Если подчиненных нет, они не включаются в результат.Если более одного подчиненного имеют одинаковую самую высокую зарплату, все они должны присутствовать в результате.

Например, это похоже на получение высокооплачиваемого сотрудника (сотрудников, если зарплата соответствует) в каждом отделе.

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;
    }
}

Например, для ввода ниже:

  • employee1 ( id: 100 ) получилemployee2, employee3, employee4 и среди этого employee3 , получившего наибольшее вознаграждение с 30000 и должно быть частью результата
  • employee2 ( id: 101 ) имеетполучил employee5, employee6, и среди них employee5 имеет самую высокую заработную плату с 20000 и должна быть частью результата
  • employee3 ( id: 102 )имеет сотрудников employee7 и employee8, и оба получают зарплату с одинаковой зарплатой из 16000 и ; выходные данные должны содержать .
  • employee8 ( id: 107 ) имеет одного подчиненного сотрудника9 с окладом 12000 и employee9 должен быть частью нашейtput

    Ниже вводится, как объяснено выше:

     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;
    
    }
    

Ниже выводится:

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]]

Объяснение:

Ответы [ 3 ]

0 голосов
/ 02 декабря 2018

Хотя Aomine объяснил, как можно оптимизировать код, я бы предпочел, чтобы вы написали его как можно более читабельным, пока вы начинаете изучать вещи, поэтому встроенное поможет вам понять, какая реальная реализация находится за кодом, который вы используете.написано:

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

    // this is your value mapper
    Function<Employee, List<Employee>> managerToSubOrdinateFunction = new Function<Employee, List<Employee>>() {
        @Override
        public List<Employee> apply(Employee employee) { // given an manager Employee
            int maxSal = employee.getSubordinates().stream() // subordinates as Stream<Employee>
                    .mapToInt(Employee::getSalary)
                    .max()// max salary amongst all subordinates
                    .orElse(Integer.MIN_VALUE);
            return employee.getSubordinates().stream()
                    .filter(s -> s.getSalary() == maxSal)// filter in only max salary subordinates
                    .collect(toList());
        }
    };

    return employees.stream()
            .filter(e -> e.getSubordinates() != null)
            .collect(Collectors.toMap(Employee::getId, managerToSubOrdinateFunction));
}
0 голосов
/ 02 декабря 2018

Вот альтернатива, в которой преобразователь значений требует одного конвейера потока.

Сгруппирует подчиненных по их зарплате в TreeMap, отсортированный в порядке убывания зарплаты, поэтому первое значение TreeMap - это список подчиненных с самой высокой зарплатой.

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

    return employees.stream()
                    .filter(e -> e.getSubordinates() != null)
                    .collect(Collectors.toMap(Employee::getId,
                                              e -> e.getSubordinates ().stream ()
                                                                       .collect (Collectors.groupingBy (Employee::getSalary,
                                                                                                        ()-> new TreeMap<>(((Comparator<Integer>)Integer::compare).reversed ()),
                                                                                                        Collectors.toList()))
                                                                       .values ()
                                                                       .iterator ()
                                                                       .next ()));

}
0 голосов
/ 02 декабря 2018

Конечно, вы можете изменить keyMapper со ссылкой на метод (Employee::getId или лямбда employee -> employee.getId()) и valueMapper (t -> { ...) на лямбду следующим образом:

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;
                        }));

Вы можете пойти дальше и упростить метод до:

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));

                        }));

и еще дальше:

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

Если у вас есть этот метод:

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));
}

Где Main относится к классу, содержащему вспомогательный метод apply.

...