Java中如何基于比较器执行排序保持原始排序的完整性
我已经介绍了Comparable vs Comparator接口的实现示例 但是,我在it的实施过程中遇到了一个问题: 假设我有一个简单的类:Employee,它有一个基于雇员姓名的默认排序机制Java中如何基于比较器执行排序保持原始排序的完整性,java,sorting,collections,comparator,comparable,Java,Sorting,Collections,Comparator,Comparable,我已经介绍了Comparable vs Comparator接口的实现示例 但是,我在it的实施过程中遇到了一个问题: 假设我有一个简单的类:Employee,它有一个基于雇员姓名的默认排序机制 public class Employee implements Comparable<Employee> { private int empSalary; private String empName; @Override public int compareT
public class Employee implements Comparable<Employee> {
private int empSalary;
private String empName;
@Override
public int compareTo(Employee e) {
return this.empName.compareTo(e.empName);
}
}
输入顺序:
Name : Kumar, Salary : 40
Name : Sanket, Salary : 10
Name : Kumar, Salary : 20
预期产出:
Name : Kumar, Salary : 20
Name : Kumar, Salary : 40
Name : Sanket, Salary : 10
实际产量:
Name : Sanket, Salary : 10 // incorrect order
Name : Kumar, Salary : 20
Name : Kumar, Salary : 40
这并不是因为您的
Employee
类已经有了默认的排序,即使用Collections.sort
和自定义比较器将引入一个新的排序层
例如,假设您的员工的默认顺序是按工资升序排列的。现在让我们假设您想按工资降序对它们进行排序
根据你的逻辑,这将如何表现
Collections.sort(employees, new SalaryDescendingComparator());
事实上,当您为Collections.sort
提供自定义比较器时,它将仅使用此比较器,而不使用您在Employee
类中实现的排序机制
作为缔约国:
根据
指定比较器
因为SalaryComparator
只根据员工的工资对员工进行比较,所以您会得到这个输出
如果您想先按姓名排序,然后按工资排序,则必须一次性完成,即:
public class Employee implements Comparable<Employee> {
private int empSalary;
private String empName;
@Override
public int compareTo(Employee e) {
int cmp = this.empName.compareTo(e.empName);
return cmp != 0 ? cmp : Integer.compare(empSalary, e.empSalary);
}
}
public类Employee实现了可比较的{
私人薪酬;
私有字符串名称;
@凌驾
公共内部比较(员工e){
int cmp=this.empName.compareTo(e.empName);
返回cmp!=0?cmp:整数。比较(empSalary,e.empSalary);
}
}
这并不是因为您的员工
类已经有了默认的排序,即使用集合。使用自定义比较器进行排序将引入一个新的排序层
例如,假设您的员工的默认顺序是按工资升序排列的。现在让我们假设您想按工资降序对它们进行排序
根据你的逻辑,这将如何表现
Collections.sort(employees, new SalaryDescendingComparator());
事实上,当您为Collections.sort
提供自定义比较器时,它将仅使用此比较器,而不使用您在Employee
类中实现的排序机制
作为缔约国:
根据
指定比较器
因为SalaryComparator
只根据员工的工资对员工进行比较,所以您会得到这个输出
如果您想先按姓名排序,然后按工资排序,则必须一次性完成,即:
public class Employee implements Comparable<Employee> {
private int empSalary;
private String empName;
@Override
public int compareTo(Employee e) {
int cmp = this.empName.compareTo(e.empName);
return cmp != 0 ? cmp : Integer.compare(empSalary, e.empSalary);
}
}
public类Employee实现了可比较的{
私人薪酬;
私有字符串名称;
@凌驾
公共内部比较(员工e){
int cmp=this.empName.compareTo(e.empName);
返回cmp!=0?cmp:整数。比较(empSalary,e.empSalary);
}
}
如果您想创建一个自定义的比较器来根据薪资区分姓名关系,请比较器首先尝试比较两名员工,然后如果这是一个关系,请使用薪资:
public class SalaryComparator implements Comparator<Employee> {
@Override
public int compare(Employee e1, Employee e2) {
if (e1.compareTo(e2) == 0)
return e1.empSalary - e2.empSalary;
return e1.compareTo(e2);
}
}
公共类SalaryComparator实现Comparator{
@凌驾
公共整数比较(员工e1、员工e2){
如果(e1.与(e2)==0相比)
返回e1.empSalary-e2.empSalary;
返回e1.compareTo(e2);
}
}
如果您想创建一个自定义的比较器来根据薪资区分姓名关系,请比较器首先尝试比较两名员工,然后如果这是一个关系,请使用薪资:
public class SalaryComparator implements Comparator<Employee> {
@Override
public int compare(Employee e1, Employee e2) {
if (e1.compareTo(e2) == 0)
return e1.empSalary - e2.empSalary;
return e1.compareTo(e2);
}
}
公共类SalaryComparator实现Comparator{
@凌驾
公共整数比较(员工e1、员工e2){
如果(e1.与(e2)==0相比)
返回e1.empSalary-e2.empSalary;
返回e1.compareTo(e2);
}
}
请注意,在Java 8中,您可以通过以下方式执行此操作:
public class Employee {
private int empSalary;
private String empName;
public int getEmpSalary() {
return empSalary;
}
public String getEmpName() {
return empName;
}
}
请注意,我添加了一个公共getter,然后对于简单比较:
List<Employee> employeeList = new ArrayList<>();
// Populate it
employeeList.sort(Comparator.comparingInt(Employee::getEmpSalary));
现在,如果要首先比较姓名和薪资,可以使用:
employeeList.sort(
Comparator.comparing(Employee::getEmpName)
.thenComparingInt(Employee::getEmpSalary)
请注意,在Java 8中,您可以通过以下方式执行此操作:
public class Employee {
private int empSalary;
private String empName;
public int getEmpSalary() {
return empSalary;
}
public String getEmpName() {
return empName;
}
}
请注意,我添加了一个公共getter,然后对于简单比较:
List<Employee> employeeList = new ArrayList<>();
// Populate it
employeeList.sort(Comparator.comparingInt(Employee::getEmpSalary));
现在,如果要首先比较姓名和薪资,可以使用:
employeeList.sort(
Comparator.comparing(Employee::getEmpName)
.thenComparingInt(Employee::getEmpSalary)
不像其他人建议的那样,创建一个包含所有条件的新比较器,您还可以多次排序
因此,如果您将排序部件替换为:
Collections.sort(employeeList, new SalaryComparator());
Collections.sort(employeeList);
然后您将获得预期的输出
与使用组合比较器同时对所有内容进行排序相比,它的效率可能更低,但当需要使用多个属性进行排序时,它非常方便
如果您真的需要一种强大的方法来按不同属性排序(如在表中),那么您应该尝试创建一个比较器链。
下面是这种模式的一个示例:
(这是使用Java8:)执行答案中建议的操作的旧方法)您也可以多次排序,而不是像其他人建议的那样创建一个包含所有条件的新比较器
因此,如果您将排序部件替换为:
Collections.sort(employeeList, new SalaryComparator());
Collections.sort(employeeList);
然后您将获得预期的输出
与使用组合比较器同时对所有内容进行排序相比,它的效率可能更低,但当需要使用多个属性进行排序时,它非常方便
如果您真的需要一种强大的方法来按不同属性排序(如在表中),那么您应该尝试创建一个比较器链。
下面是这种模式的一个示例:
(这是使用Java8执行答案中建议的操作的老方法:)