问题
I have the following list of Employee data which I need to group based on the employee department and then I want to find the 2 highest-paid employees in each department.
public class Employee {
private int id;
private String name;
private String dept;
private int salary;
//setters and getters
}
List<Employee> listOfEmp = new ArrayList<>();
listOfEmp.add(new Employee (1, "A", "IT",100));
listOfEmp.add(new Employee (2, "B", "IT",200));
listOfEmp.add(new Employee (3, "C", "SUPPORT",100));
listOfEmp.add(new Employee (4, "D", "SUPPORT",200));
listOfEmp.add(new Employee (5, "E", "SUPPORT",300));
listOfEmp.add(new Employee (6, "F", "SUPPORT",400));
listOfEmp.add(new Employee (7, "G", "IT",500));
listOfEmp.add(new Employee (8, "H", "IT",600));
listOfEmp.add(new Employee (9, "I", "IT",700));
following is the query I have written to group employees by department
Map<String, List<String>> departmentWiseEmployees = listOfEmp.stream().
collect(Collectors.groupingBy(Employee::getDept, Collectors.mapping(Employee::getName, toList())));
I am trying to use the following method to find the highest 2 paid employees in each department using the following method. but it is
int limit = 2;
Map<String, List<String>> groupByTeachers =
listOfEmp.stream()
.collect(
Collectors.groupingBy(
Employee::getDept,
Collectors.collectingAndThen(
Collectors.toList(),
e -> e.stream().sorted().limit(limit).collect(toList() ) ) ) );
here compiler complains about following error on the lambda parameter provided for collectingAndThen
, it says e is of type List<Employee>
but it has to be List<Object>
Could somebody help me to understand what is going wrong here?
回答1:
This part of code:
e -> e.stream().sorted().limit(limit).collect(Collectors.toList())
return List of List<Employee>
and not List<String>
, so either you change the type of the result to:
Map<String, List<Employee>> groupByTeachers =
// ...The rest of your code
Or if you expect Map<String, List<String>>
, change the collectingAndThen
to get the expected field, for example getName
or getDep
:
e -> e.stream().sorted().limit(limit)
.map(Employee::getDep) // for example getDep
.collect(Collectors.toList())
回答2:
Here is the final answer for those who are interested.
Map<String, List<String>> groupByTeachers =
listOfEmp.stream()
.collect(
Collectors.groupingBy(
Employee::getDept,
Collectors.collectingAndThen(
Collectors.toList(),
e -> e.stream().sorted(Comparator.comparingLong(Employee::getSalary).reversed()).limit(limit).map(Employee::getName).collect(toList() ) ) ) );
回答3:
What you are looking for is to 1. group by department 2. then from the grouped entries, stream on the values, sort them based on an attribute and finally limit N values of it. This could be transformed into the code as:
Map<String, List<String>> highestPaidEmployeesGroupByDepartment = listOfEmp.stream()
.collect(Collectors.collectingAndThen(Collectors.groupingBy(Employee::getDept),
// part 2 starting here
m -> m.entrySet().stream()
.map(e -> Map.entry(e.getKey(), e.getValue().stream()
.sorted(Comparator.comparing(Employee::getSalary).reversed())
.limit(limit)
.map(Employee::getName)
.collect(Collectors.toList())))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))));
or an alternative without the collectingAndThen
would be
Map<String, List<String>> collect = listOfEmp.stream()
.collect(Collectors.groupingBy(Employee::getDept))
.entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().stream()
.sorted(Comparator.comparing(Employee::getSalary).reversed())
.limit(limit)
.map(Employee::getName)
.collect(Collectors.toList())));
来源:https://stackoverflow.com/questions/62679962/how-to-apply-sorting-and-limiting-after-groupby-using-java-streams