【问题标题】:Java Sorting Objects with Multiple ParametersJava 使用多个参数对对象进行排序
【发布时间】:2012-04-04 17:44:26
【问题描述】:

我最近一直致力于更好地理解排序算法及其与不同类型输入的关系。目前,我正在开发一个学生管理程序,其中每个学生都有三个参数:姓氏、GPA 和用户 ID(字符串、双精度、整数)。它们每个都存储在具有这三个参数的 Student 类中,并且有 DOZENS 学生(该程序的一个关键功能是输入、删除和更新学生)。

我的问题是:使用主要的排序算法(合并排序、快速排序等),按每个参数对我的学生列表进行排序的最佳方法是什么?例如,执行合并排序以按 GPA 对列表进行排序的最佳方法是什么?或者使用快速排序按姓氏对列表进行排序?

基本上我的问题归结为...如果这些对象没有三个参数,我可以对它们进行排序(编写一个合并排序来对 100 个数字进行排序对我来说非常容易)。如何管理其他两个参数并确保它们在排序后可访问?

【问题讨论】:

  • 家庭作业(几周前到期)是学习如何硬编码合并排序以对 100 个整数的列表进行排序。当我开始从事更大的项目时,我只是想了解 Java 工具的局限性。

标签: java sorting object


【解决方案1】:

在 Java 中这样做的方式是使用不同的Comparators。然后你说:

Collections.sort(list, new NameComparator());

或者

Collections.sort(list, new GpaComparator());

这些比较器使用不同的字段来定义两个元素之间的顺序。

例如,名称比较器可能是:

class NameComparator implements Comparator< Student> {
    @Override public int compare(Student left, Student right) {
        return left.getName().compareTo(right.getName());
    }
}

而 GpaComparator 可能是

class GpaComparator implements Comparator< Student> {
    @Override public int compare(Student left, Student right) {
        if (left.getGpa() < right.getGpa()) {
            return -1;
       } else if (left.getGpa() > right.getGpa()) {
            return 1;
       } else {
           return 0;
     }
 }

【讨论】:

  • 编写GPAComparator 的更好方法是使用Integer 对象而不是原语,然后将它们委托给.compare() 方法。然后 if/elseif/else 块变成单行。
【解决方案2】:

执行此操作的典型方法是对接受Comparator 的任何类型编写通用排序算法,然后编写不同的Comparators 以按不同字段排序。

【讨论】:

    【解决方案3】:

    我建议像这样在Student 类中实现Comparable 接口

    public class Student implements Comparable {
       public int compareType; //you can make this an enum if you want
       ...
    
       public int compareTo(Object o) {
           if(compareType == 0) 
             return gpaCompareTo(o);
           else if(compareType == 1)
             return nameCompareTo(o);
    
           return idCompateTo(o); 
       }
    
       public int gpaCompareTo(Object o) {
           //implement your gpaCompareTo
       }
    
       public int nameCompareTo(Object o) {
           //implement your nameCompareTo
       }
    
       public int idCompareTo(Object o) {
           //implement your idCompareTo
       }
    }
    

    然后使用像

    这样的内置排序
    List<Student> list = new ArrayList<Student>();
    ...
    Collections.sort(list);
    

    或者你不能实现Comparable并设计你自己的比较器

    public class MyComparator implements Comparator<Student> {
    
       public int compare(Student o1, Student o2) {
          //implement the comparator
       }
    
       public boolean equals(Object o) {
          //implement the equals 
       }
    }
    

    那么你可以使用其他Collection's排序方法

    Collections.sort(list, MyComparator);
    

    【讨论】:

    • Comparable 仅在您每次都按相同内容排序时才有效。
    【解决方案4】:

    这可能是题外话,但如果你想尝试一些很酷的东西,JDK 8 Lambda Preview 提供了一些很酷的方法来使用Lamda expressions and method references 定义比较器。

    假设我们有一个类:

    class Jedi  {
       private final String name;
       private final int age;
       //...
    }
    

    然后是它们的集合:

    List<Jedi> jediAcademy = asList(new Jedi("Obiwan",80), new Jedi("Anakin", 30));
    sort(jediAcademy, (j1, j2) -> j1.getAge() > j2.getAge() ? 1 : j1.getAge() < j2.getAge() ? -1 : 0);
    System.out.println(jediAcademy); //Anakin, Obiwan
    

    或者使用方法引用,假设 Jedi 具有充当比较器的方法(相同的签名)

    class Jedi  {
      public static int compareByAge(Jedi first, Jedi second){
         return first.age > second.age ? 1 : first.age < second.age ? -1 : 0;
      }
       //...
    }
    

    可以通过使用方法引用来生成比较器,如下所示:

    List<Jedi> jediAcademy = asList(new Jedi("Obiwan",80), new Jedi("Anakin", 30));
    sort(jediAcademy, Jedi::compareByAge);
    System.out.println(jediAcademy);//Anakin, Obiwan
    

    【讨论】:

    • +1:非常酷的比较器方式。我想我们很快就会看到这样的深度集成。非常容易使用。
    • @Mathew 事实上,您现在可以通过下载并安装我在上面分享的预览版来尝试一下 :-)
    【解决方案5】:

    其实和排序数字没什么区别,只不过在这种情况下你的“数字”是你用户的三个字段,每个数字的值受每个字段的值的约束,字段的顺序决定了排序排名。

    更具体地说,您有一个包含 3 个字段的元组:&lt;GPA, Last Name, User ID&gt;,假设您要按 GPA、姓氏和用户 ID 排序。

    与 219 排在 139 之上的方式相同(即,即使“十”位较低,“百”位具有更高的值),像&lt;3.75, Jones, 5&gt; 这样的元组将排在&lt;3.0, Adams, 2&gt; 之上,因为“GPA 数字”(更重要)具有更高的值,即使“姓氏数字”较低(例如,琼斯“低于”亚当斯)。

    【讨论】:

      【解决方案6】:

      使用多个比较器

      class Student
      {
      
              String lastName;
              dounle GPA;
              int userId
      
      
          static Comparator<Student> getStudentLastNameComparator() {
              return new Comparator<Student>() {
      
                  @Override
                  public int compare(Student Student1, Student Student2) {
                      return Student1.getlastName().compareTo(Student2.getlastName());
                  }
                  // compare using Student lastName
              };
          }
      
          static Comparator<Student> getStudentGPAComparator() {
              return new Comparator<Student>() {
      
                  @Override
                  public int compare(Student Student1, Student Student2) {
                      if(Student1.GPA < Student2.GPA)
                          return 1;
                      else
                          return -1;
                  }
                  // compare using Student GPA
              };
          }
      
          static Comparator<Student> getStudentUserIdComparator() {
              return new Comparator<Student>() {
      
                  @Override
                  public int compare(Student Student1, Student Student2) {
                      if(Student1.userId < Student2.userId)
                          return 1;
                      else
                          return -1;
                  }
                  // compare using Student userId
              };
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-12-23
        • 2018-08-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-07-07
        相关资源
        最近更新 更多