有效地对逻辑上属于同一实体的对象列表进行排序

时间:2015-08-09 17:57:22

标签: java performance sorting data-structures collections

我有一系列对象,我想以特定的方式排序 例如:
我的课程Employee有一个属性departmentId EmployeedepartmentId个对象的实例具有相同的List<Employee> employees值 员工也有工资属性 所以我想要排序(John, 10000, A) (Jane, 30000, A) (Bill, 32000, A) (Jim, 12000, B) (Jake, 50000, B) (James, 14000, C) 个对象,以便排序顺序如下:
薪水最低的员工首先在列表中,然后是按同一部门的薪水排序的所有其他员工。 然后,在该部门的最后一名员工之后,我希望下一个部门的员工薪水低于所有其他部门,其余的员工排序等。 例如。

ng-view

实现这一目标的最有效方法是什么?我想使代码尽可能紧凑和高效,而不是创建临时匿名类将它们添加到哈希映射(除非这是唯一有效的方法)。

注意:
我知道比较器和类似的等。
我的问题不在于如何实际排序(我知道实现比较器)但是如何有效地完成这样的代码,最好避免一堆临时匿名对象

另外:我没有使用Java 8,并希望使用简单的Java方法

更新
回应评论。我希望那个工资最低,然后是下一个最高等级的部门

2 个答案:

答案 0 :(得分:2)

我个人使用Employee类和Department类,两者都会扩展Comparable<T>接口以利用库功能。

以下是一个Department类的示例,该类具有名称和员工列表,这些列表在构造时进行排序。您可能希望对getEmployees()上的列表进行浅层复制,以防止其他人更改其顺序:

class Department implements Comparable<Department> {

    private List<Employee> employees;
    private char name;

    public Department(char name, List<Employee> employees) {
        // avoid mutating original list
        this.employees = new ArrayList<Employee>(employees);
        this.name = name;

        Collections.sort(this.employees);
    }

    @Override
    public int compareTo(Department other) {
        if (other == null) {
            return 1;
        }
        // employees are sorted by salary within their department.
        // all we need is to compare the lowest-salary employees
        // from both departments
        return this.employees.get(0).getSalary()
                - other.employees.get(0).getSalary();
    }

    public List<Employee> getEmployees() {
        return this.employees;
    }

    public char getName() {
        return this.name;
    }
}

现在Employee类只需要使用薪水比较来实现compareTo(Employee other)

class Employee implements Comparable<Employee> {

    private String name;
    private int salary;

    public Employee(String name, int salary) {
        this.name = name;
        this.salary = salary;
    }

    @Override
    public int compareTo(Employee other) {
        if (other == null) {
            return 1;
        }
        return this.salary - other.salary;
    }

    @Override
    public String toString() {
        return "Employee [name=" + name + ", salary=" + salary + "]";
    }

    public String getName() {
        return name;
    }

    public int getSalary() {
        return salary;
    }

}

这应该允许您在部门列表上使用Collections.sort并获得正确的订单。这是一个完整的例子:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Fiddles {

    static class Department implements Comparable<Department> {

        private List<Employee> employees;
        private char name;

        public Department(char name, List<Employee> employees) {
            // avoid mutating original list
            this.employees = new ArrayList<Employee>(employees);
            this.name = name;

            Collections.sort(this.employees);
        }

        @Override
        public int compareTo(Department other) {
            if (other == null) {
                return 1;
            }
            return this.employees.get(0).getSalary()
                    - other.employees.get(0).getSalary();
        }

        public List<Employee> getEmployees() {
            return this.employees;
        }

        public char getName() {
            return this.name;
        }
    }

    static class Employee implements Comparable<Employee> {

        private String name;
        private int salary;

        public Employee(String name, int salary) {
            this.name = name;
            this.salary = salary;
        }

        @Override
        public int compareTo(Employee other) {
            if (other == null) {
                return 1;
            }
            return this.salary - other.salary;
        }

        @Override
        public String toString() {
            return "Employee [name=" + name + ", salary=" + salary + "]";
        }

        public String getName() {
            return name;
        }

        public int getSalary() {
            return salary;
        }

    }

    public static void main(String args[]) {
        final Department A = new Department('A', new ArrayList<Employee>() {
            {
                add(new Employee("John", 10000));
                add(new Employee("Jane", 30000));
                add(new Employee("Bill", 32000));
            }
        });
        final Department B = new Department('B', new ArrayList<Employee>() {
            {
                add(new Employee("Jim", 12000));
                add(new Employee("Jake", 50000));
            }
        });

        final Department C = new Department('C', new ArrayList<Employee>() {
            {

                add(new Employee("James", 14000));

            }
        });

        List<Department> departments = new ArrayList<Department>() {
            {
                add(A);
                add(B);
                add(C);
            }
        };
        Collections.shuffle(departments);
        Collections.sort(departments);
        for (Department department : departments) {
            for (Employee e : department.getEmployees()) {
                System.out.println(String.format(
                        "Employee: %s, Salary: %d, department: %s",
                        e.getName(), e.getSalary(), department.getName()));
            }
        }
    }
}

答案 1 :(得分:2)

我认为最简单的方法是:

  1. 从每个部门ID准备一个Map到该部门的最低工资。这需要在列表中扫描一次(O(n))。
  2. 制作一个使用该地图的比较器。它只是一个对象。比较器进行排序,以便:
    • 如果两名员工在同一个部门,请比较他们的工资。
    • 如果两个部门不同,请根据上面的地图比较他们的最低工资。
    • 如果他们具有相同的等级(最低工资),则按其ID排序(否则您可能会得到两个具有相同最低工资的部门)。
    • 否则比较他们的等级。
  3. 所以这是一个演示(编辑:操作现在封装在Employee类中。但它的工作是相同的):

    public class Employee {
    
        private String name;
        private int salary;
        private String department;
    
    
        /**
         * Comparator - Note that it has a constructor that takes a department ranking
         * list, which should be prepared in advance
         */
        private static class DepartmentAndSalaryComparator implements Comparator<Employee>{
    
            Map<String,Integer> departmentRanking;
    
            public DepartmentAndSalaryComparator(Map<String,Integer> departmentRanking) {
                this.departmentRanking = departmentRanking;
            }
    
            @Override
            public int compare(Employee o1, Employee o2) {
    
                // If employees belong to the same department, rank them by salary
    
                if ( o1.department.equals(o2.department )) {
                    return o1.salary - o2.salary;
                }
    
                // Get the lowest salaries for the departments of the respective employees
    
                int o1Rank = departmentRanking.get(o1.department);
                int o2Rank = departmentRanking.get(o2.department);
    
                if ( o1Rank == o2Rank ) {
                    return o1.department.compareTo(o2.department);
                }
    
                return o1Rank - o2Rank;
    
            }
        }
    
        public Employee(String name, int salary, String department) {
            this.name = name;
            this.salary = salary;
            this.department = department;
        }
    
        /**
         * Creates a map of department id to minimum salary in that department
         * from a given list of employees.
         * This operation is O(n)
         * @param employees List of employees for which to calculate map
         * @return Map of department rankings
         */
        private static Map<String,Integer> calculateDepartmentRanking( List<Employee> employees ) {
            Map<String,Integer> rankings = new HashMap<>();
    
            for ( Employee emp : employees ) {
                Integer currMin = rankings.get(emp.department);
                if ( currMin == null || currMin > emp.salary ) {
                    rankings.put(emp.department, emp.salary);
                }
            }
            return rankings;
        }
    
        /**
         * Static method to sort a list of employees by Department, then by Salary, where
         * the order of department is based on the minimum salary in that department.
         * This operation is O(n log n)
         * 
         * @param employees The list of employees to sort
         */
        public static void sortListBySalaryBasedDepartment( List<Employee> employees ) {
            Collections.sort(employees, new DepartmentAndSalaryComparator(calculateDepartmentRanking(employees)));
        }
    
        @Override
        public String toString() {
            return String.format("Employee: name=%s, salary=%d, dept.=%s",
                                 name,
                                 salary,
                                 department);
        }
    
        public static void main(String[] args) {
    
           // Create example list and shuffle it to make sure it's not ordered
    
            List<Employee> employees = Arrays.asList(
                    new Employee("Millie", 12000, "Accounts"),
                    new Employee("Morris", 21200, "Accounts"),
                    new Employee("Jerry", 22000, "Accounts"),
                    new Employee("Ellen", 17000, "Sales"),
                    new Employee("Sandy", 12500, "Technology"),
                    new Employee("Jack", 40000, "Technology")
               );
    
            Collections.shuffle(employees);
    
            // Sort using the special comparator
    
            Employee.sortListBySalaryBasedDepartment(employees);
    
            for (Employee e : employees) {
                System.out.println(e);
            }
    
        }
    }
    

    输出:

    Employee: name=Millie, salary=12000, dept.=Accounts
    Employee: name=Morris, salary=21200, dept.=Accounts
    Employee: name=Jerry, salary=22000, dept.=Accounts
    Employee: name=Sandy, salary=12500, dept.=Technology
    Employee: name=Jack, salary=40000, dept.=Technology
    Employee: name=Ellen, salary=17000, dept.=Sales