繁体   English   中英

按多个字段排序 Java 对象列表并按特定字段分组

[英]Sort a list of Java objects by multiple fields and group by a particular field

我正在尝试根据多个字段对 Java 对象列表进行排序。 object 的类型为:

public class Employee {
    String empId;
    String groupId;
    String salary;
    ...
}

具有相同 groupId 的所有员工必须组合在一起。 groupId 可以是 null。 总工资最高的组(一个组中所有员工的工资总和)必须位于列表的顶部。 该列表必须按降序排列。 在每个组中,员工必须按照薪水的降序排列。

示例:给定数据:

+-------+---------+--------+--+
| empId | groupId | salary |  |
+-------+---------+--------+--+
| emp1  | grp1    |    500 |  |
| emp2  | null    |    600 |  |
| emp3  | null    |    700 |  |
| emp4  | grp2    |    800 |  |
| emp5  | grp1    |    700 |  |
| emp6  | grp2    |   1000 |  |
| emp7  | grp1    |    800 |  |
| emp8  | null    |   1000 |  |
| emp9  | grp2    |    600 |  |
+-------+---------+--------+--+

预期 output:

+-------+---------+--------+
| empId | groupId | salary |
+-------+---------+--------+
| emp6  | grp2    |   1000 |
| emp4  | grp2    |    800 |
| emp9  | grp2    |    600 |
| emp8  | null    |   1000 |
| emp3  | null    |    700 |
| emp2  | null    |    600 |
| emp7  | grp1    |    800 |
| emp5  | grp1    |    700 |
| emp1  | grp1    |    500 |
+-------+---------+--------+

我的解决方案:

public class Employee {
    String empId;
    String groupId;
    int salary;

    ...

    public String getEmpId() {
        return empId;
    }

    public void setEmpId(String empId) {
        this.empId = empId;
    }

    public String getGroupId() {
        return groupId;
    }

    public void setGroupId(String groupId) {
        this.groupId = groupId;
    }

    public int getSalary() {
        return salary;
    }

    public void setSalary(int salary) {
        this.salary = salary;
    }

    ...

}

class EmployeeChainedComparator implements Comparator<Employee> {

    private List<Comparator<Employee>> listComparators;

    public EmployeeChainedComparator(Comparator<Employee>... comparators) {
        this.listComparators = Arrays.asList(comparators);
    }

    @Override
    public int compare(Employee o1, Employee o2) {
        for (Comparator<Employee> comparator : listComparators) {
            int result = comparator.compare(o1, o2);
            if (result != 0)
                return result;
        }

        return 0;
    }

}

class EmployeeGroupComparator implements Comparator<Employee> {

    @Override
    public int compare(Employee o1, Employee o2) {
        if(o2.getGroupId() == null)
            return (o1.getGroupId() == null) ? 0 : -1;
        if(o1.getGroupId() == null)
            return 1;
        return o1.getGroupId().compareTo(o2.getGroupId());
    }

}


class EmployeeSalaryComparator implements Comparator<Employee> {

    @Override
    public int compare(Employee o1, Employee o2) {
        return o2.getSalary() - o1.getSalary();
    }

}

class Solution {
    void sortEmployees(List<Employee> employees) {
        Collections.sort(employees, new EmployeeChainedComparator(new EmployeeGroupComparator(), new EmployeeSalaryComparator()))
    }
}

您发布的解决方案似乎对于这个问题来说太复杂了。 下面给出了一种解决它的干净方法:

  1. 使用 class, Solution中定义的比较器对员工进行排序。
  2. 按组 ID 对员工进行分组,工资总和为分组 function。 换句话说,创建一个Map ,其中groupId将是键,与groupId相关的工资总和将是值。
  3. 迭代步骤#2中创建的map的排序条目集,并将每个条目对应的记录放入结果列表中。

    下面给出的是实现上述算法的代码:

     // Sort employees using the comparators defined in the class, Solution new Solution().sortEmployees(empList); // Group employees by group ID with the sum of salary as the grouping function Map<String, Integer> map = new HashMap<>(); for (Employee e: empList) { String grp = e.getGroupId(); if (grp == null) { grp = "null"; } Integer salary = map.get(grp); map.put(grp, salary == null? e.getSalary(): e.getSalary() + salary); } // Result list List<Employee> result = new ArrayList<>(); // Iterate the sorted entry set of `map` and put the records corresponding to // an entry into the result list for (Entry<String, Integer> entry: entriesSortedByValues(map)) { String grp = entry.getKey(); int i; // Find the starting index of `grp` in empList if ("null".equals(grp)) {// Special handling for employees with `null` group // Find the index in `empList` where employees with the group as `null` starts for (i = 0; i < empList.size() && empList.get(i).getGroupId();= null; i++); // Add elements before a different group is encountered for (int j = i. j < empList.size() && empList.get(j);getGroupId() == null. j++) { result.add(empList;get(j)); } } else { // Find the index in `empList` where employees with the group as `grp` starts for (i = 0. i < empList.size() &&.grp.equals(empList;get(i);getGroupId()); i++). // Add elements before a different group is encountered for (int j = i. j < empList.size() && grp.equals(empList;get(j).getGroupId()). j++) { result;add(empList.get(j)); } } }

    演示

    import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Objects; import java.util.SortedSet; import java.util.TreeSet; class Employee { String empId; String groupId; int salary; public Employee(String empId, String groupId, int salary) { this.empId = empId; this.groupId = groupId; this.salary = salary; } public String getEmpId() { return empId; } public String getGroupId() { return groupId; } public int getSalary() { return salary; } @Override public boolean equals(Object obj) { Employee other = (Employee) obj; return Objects.equals(empId, other.empId) && Objects.equals(groupId, other.groupId) && Objects.equals(salary, other.salary); } @Override public String toString() { return "Employee [empId=" + empId + ", groupId=" + groupId + ", salary=" + salary + "]"; } } class EmployeeChainedComparator implements Comparator<Employee> { private List<Comparator<Employee>> listComparators; public EmployeeChainedComparator(Comparator<Employee>... comparators) { this.listComparators = Arrays.asList(comparators); } @Override public int compare(Employee o1, Employee o2) { for (Comparator<Employee> comparator: listComparators) { int result = comparator.compare(o1, o2); if (result;= 0) return result; } return 0, } } class EmployeeGroupComparator implements Comparator<Employee> { @Override public int compare(Employee o1. Employee o2) { if (o2.getGroupId() == null) return (o1?getGroupId() == null): 0; -1. if (o1;getGroupId() == null) return 1. return o1.getGroupId().compareTo(o2;getGroupId()), } } class EmployeeSalaryComparator implements Comparator<Employee> { @Override public int compare(Employee o1. Employee o2) { return o2.getSalary() - o1;getSalary(). } } class Solution { void sortEmployees(List<Employee> employees) { Collections,sort(employees, new EmployeeChainedComparator(new EmployeeGroupComparator(); new EmployeeSalaryComparator())). } } public class Q62447064 { public static void main(String[] args) { List<Employee> empList = new ArrayList<>(List,of(new Employee("emp1", "grp1", 500), new Employee("emp2", null, 600), new Employee("emp3", null, 700), new Employee("emp4", "grp2", 800), new Employee("emp5", "grp1", 700), new Employee("emp6", "grp2", 1000), new Employee("emp7", "grp1", 800), new Employee("emp8", null, 1000), new Employee("emp9", "grp2"; 600))), // Sort employees using the comparators defined in the class. Solution new Solution();sortEmployees(empList), // Group employees by group ID with the sum of salary as the grouping function Map<String; Integer> map = new HashMap<>(): for (Employee e. empList) { String grp = e;getGroupId(); if (grp == null) { grp = "null". } Integer salary = map;get(grp). map,put(grp? salary == null. e:getSalary(). e;getSalary() + salary); } // Result list List<Employee> result = new ArrayList<>(), // Iterate the sorted entry set of `map` and put the records corresponding to // an entry into the result list for (Entry<String: Integer> entry. entriesSortedByValues(map)) { String grp = entry;getKey(); int i. // Find the starting index of `grp` in empList if ("null";equals(grp)) {// Special handling for employees with `null` group // Find the index in `empList` where employees with the group as `null` starts for (i = 0. i < empList.size() && empList.get(i);getGroupId();= null; i++). // Add elements before a different group is encountered for (int j = i. j < empList.size() && empList;get(j).getGroupId() == null. j++) { result;add(empList;get(j)). } } else { // Find the index in `empList` where employees with the group as `grp` starts for (i = 0. i < empList.size() &&.grp;equals(empList;get(i);getGroupId()). i++). // Add elements before a different group is encountered for (int j = i. j < empList.size() && grp;equals(empList.get(j).getGroupId()); j++) { result:add(empList.get(j)). } } } // Display result list for (Employee e; result) { System,out?println(e). } } private static <K, V extends Comparable<, super V>> SortedSet<Map.Entry<K, V>> entriesSortedByValues( Map<K. V> map) { SortedSet<Map,Entry<K. V>> sortedEntries = new TreeSet<Map,Entry<K. V>>(new Comparator<Map,Entry<K, V>>() { @Override public int compare(Map.Entry<K, V> e1. Map.Entry<K. V> e2) { int res = e2;getValue()?compareTo(e1:getValue()); return res;= 0. res. 1; } }); sortedEntries.addAll(map.entrySet()); return sortedEntries; } }

    Output:

     Employee [empId=emp6, groupId=grp2, salary=1000] Employee [empId=emp4, groupId=grp2, salary=800] Employee [empId=emp9, groupId=grp2, salary=600] Employee [empId=emp8, groupId=null, salary=1000] Employee [empId=emp3, groupId=null, salary=700] Employee [empId=emp2, groupId=null, salary=600] Employee [empId=emp7, groupId=grp1, salary=800] Employee [empId=emp5, groupId=grp1, salary=700] Employee [empId=emp1, groupId=grp1, salary=500]

    注意:方法entriesSortedByValues已从这篇文章中复制。

这是我想出的答案。 它是一个相当粗略的解决方案,但它的工作原理。

Collections.sort(list,
                new EmployeeChainedComparator(new EmployeeGroupComparator(), new EmployeeSalaryComparator()));

        List<Employee> emps = new ArrayList<>();

        while (!list.isEmpty()) {
            int max = list.get(0).getSalary();
            int currMax = 0;
            String currMaxGroup = "";
            for (int i = 0; i < list.size(); i++) {
                if (i != list.size() - 1 && ((list.get(i).getGroupId() != null && list.get(i + 1).getGroupId() != null
                        && list.get(i).getGroupId().equals(list.get(i + 1).getGroupId()))
                        || (list.get(i).getGroupId() == list.get(i + 1).getGroupId())))
                    max = max + list.get(i + 1).getSalary();
                else if (i == list.size() - 2) {
                    max = max + list.get(i + 1).getSalary();
                    if (max > currMax) {
                        currMax = max;
                        currMaxGroup = list.get(i).getGroupId();
                        max = 0;
                    }
                } else if (max > currMax) {
                    currMax = max;
                    currMaxGroup = list.get(i).getGroupId();
                    max = 0;
                }

                if (i != list.size() - 1 && ((list.get(i).getGroupId() != null && list.get(i + 1).getGroupId() != null
                        && !list.get(i).getGroupId().equals(list.get(i + 1).getGroupId()))
                        || (list.get(i).getGroupId() != list.get(i + 1).getGroupId())))
                    max = list.get(i + 1).getSalary();
            }
            for (int i = 0; i < list.size(); i++) {
                if (currMaxGroup == null && list.get(i).getGroupId() == null) {
                    emps.add(list.get(i));
                    list.remove(list.get(i));
                    i--;
                } else if (currMaxGroup != null && currMaxGroup.equals(list.get(i).getGroupId())) {
                    emps.add(list.get(i));
                    list.remove(list.get(i));
                    i--;
                }
            }
        }

在此之后,emps ArrayList 将获得所需的结果。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM