How to apply sorting and limiting after groupby using Java streams

老子叫甜甜 提交于 2020-12-26 04:23:50

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!