【问题标题】:How to perform sorting based on Comparator keeping original sort intact in Java如何基于 Comparator 执行排序,在 Java 中保持原始排序不变
【发布时间】:2014-05-01 16:02:54
【问题描述】:

我一直在浏览 Comparable vs Comparator 接口的实现示例。

但是,我在它的实施过程中遇到了一个问题:

假设,我有一个简单的类:Employee,它有一个基于员工姓名的默认排序机制。

public class Employee implements Comparable<Employee> {

   private int empSalary;
   private String empName;

   @Override
   public int compareTo(Employee e) {
        return this.empName.compareTo(e.empName);
   }

}

但是,比方说,我必须先根据员工姓名排序,然后如果两个员工姓名相同,我必须根据他们的薪水对他们进行排序。

所以,我写了一个自定义比较器来根据薪水进行排序,如下所示

public class SalaryComparator implements Comparator<Employee> {

      @Override
      public int compare(Employee e1, Employee e2)  {
        return e1.empSalary - e2.empSalary;
      }

}

但是,当我运行我的测试类以首先根据姓名排序,其次是薪水时,输出与预期不符。

Collections.sort(employeeList, new SalaryComparator());

输入顺序:

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

【问题讨论】:

    标签: java sorting collections comparator comparable


    【解决方案1】:

    您也可以多次排序,而不是像其他人建议的那样创建一个包含所有条件的新比较器。

    所以如果你用这个替换你的排序部分:

    Collections.sort(employeeList, new SalaryComparator());
    Collections.sort(employeeList);
    

    然后您将获得预期的输出。

    它可能比使用组合比较器同时排序所有内容效率低,但当您需要使用多个属性进行排序时,它非常方便。

    如果您确实需要一种强大的按不同属性排序的方法(例如在表格中),那么您应该尝试创建一个比较器链。
    这是这种模式的一个示例:
    http://commons.apache.org/proper/commons-collections/javadocs/api-2.1.1/org/apache/commons/collections/comparators/ComparatorChain.html
    (这是使用 Java8 执行答案中建议的旧方法:)

    【讨论】:

      【解决方案2】:

      这并不是因为您的 Employee 类已经具有默认排序,而是将 Collections.sort 与自定义比较器一起使用会引入新的排序层。

      例如,假设您的Employees 的默认排序是按他们的薪水升序排列。现在假设您想按薪水降序对它们进行排序。

      根据你的逻辑,这将如何表现?

      Collections.sort(employees, new SalaryDescendingComparator());
      

      事实是,当您为Collections.sort 提供自定义比较器时,它将仅使用这个比较器,而不是您在Employee 类中实现的排序机制。

      正如doc 所说:

      根据由 指定的比较器。

      因此,因为 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);
         }
      
      }
      

      【讨论】:

        【解决方案3】:

        请注意,您可以在 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));
        

        这将创建一个Comparator&lt;Employee&gt; 来比较Employee.getEmpSalary() 返回的整数值,我在那里使用方法引用,这是写employee -&gt; employee.getEmpSalary() 的一种奇特方式,它是从Employee 映射的lambda 函数到int

        你可以使用反向:

        employeeList.sort(Comparator.comparingInt(Employee::getEmpSalary).reversed());
        

        现在如果你想先比较名字和薪水,你可以使用:

        employeeList.sort(
                Comparator.comparing(Employee::getEmpName)
                .thenComparingInt(Employee::getEmpSalary)
        

        【讨论】:

          【解决方案4】:

          如果您想创建一个自定义比较器以根据薪水区分姓名关系,请先让比较器尝试比较两个员工,然后如果是相同的,请使用薪水:

          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);
              }
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2020-03-19
            • 2011-02-19
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-04-15
            • 2021-11-14
            相关资源
            最近更新 更多