Java比较器多字段排序不起作用

Posted

技术标签:

【中文标题】Java比较器多字段排序不起作用【英文标题】:Java Comparator Multiple field sort not working 【发布时间】:2016-03-25 21:03:17 【问题描述】:

我正在尝试按姓氏降序排序,然后是等级,并且一直在关注这个example。

我只是通过姓氏排序而不是等级排序。我没有得到什么?

@Override
public int compare(Student o1, Student o2) 
    int c;
    c = o1.getLastName().compareToIgnoreCase(o2.getLastName());
    if (c == 0) 
        c = Double.compare(o1.getGrade(), o2.getGrade());
    
    return c;

我并没有完全理解上面提到的例子在 c == 0 方面是如何工作的,因为 c 在排序时永远不会等于零。这让我明白了为什么成绩没有排序,但这并没有把我带到我需要的地方。

排序在这里执行:

@Override
public void execute(List<Student> list) 
    LastNameComparator cmp = new LastNameComparator(studentList);
    Collections.sort(studentList, cmp);


而测试类是这样的:

public static void main(String[] args) 
    // TODO code application logic here

    for (int i = 0; i < 20; i++) 
        Student student = new Student(randomInteger(1,50), NameGenerator.generateName(), NameGenerator.generateName(), Math.round(Math.random()*10.0)/10.0);
        studentList.add(student);
    
    System.out.println("--Unsorted--");

    for (Student student : studentList) 
        System.out.println(student.getStudentID());
        System.out.println(student.getFirstName());
        System.out.println(student.getLastName());
        System.out.println(student.getGrade());
    

    Command sortLastName = new LastNameComparator(studentList);
    sortLastName.execute(studentList);

    System.out.println("--Sorted--");


    for (Student student : studentList) 
        System.out.println(student.getStudentID());
        System.out.println(student.getFirstName());
        System.out.println(student.getLastName());
        System.out.println(student.getGrade());
    

名称是这样生成的。我从here得到它:

public class NameGenerator 
    private static String[] Beginning =  "Kr", "Ca", "Ra", "Mrok", "Cru",
         "Ray", "Bre", "Zed", "Drak", "Mor", "Jag", "Mer", "Jar", "Mjol",
         "Zork", "Mad", "Cry", "Zur", "Creo", "Azak", "Azur", "Rei", "Cro",
         "Mar", "Luk" ;
   private static String[] Middle =  "air", "ir", "mi", "sor", "mee", "clo",
         "red", "cra", "ark", "arc", "miri", "lori", "cres", "mur", "zer",
         "marac", "zoir", "slamar", "salmar", "urak" ;
   private static String[] End =  "d", "ed", "ark", "arc", "es", "er", "der",
         "tron", "med", "ure", "zur", "cred", "mur" ;

   private static Random rand = new Random();

   public static String generateName() 

      return Beginning[rand.nextInt(Beginning.length)] + 
            Middle[rand.nextInt(Middle.length)]+
            End[rand.nextInt(End.length)];

   
 

更新 我知道这只有在名称相同的情况下才有效。这是对我不起作用的地方,因为随机名称生成器很少有机会生成两次相同的名称。我正在研究如何让列表按姓氏按降序排序,然后按等级排序,无论名称是否相同。如果名字相同,则等级高。

【问题讨论】:

c 应该等于 0 如果姓氏相同。因此,如果您有多个姓氏为“Smith”的人,那么“Smith's”将根据等级进行排序。您提供的代码应该可以做到这一点。 您的代码非常混乱。 execute 方法对传递给它的列表进行排序。 为什么你的参数的构造函数要带参数?这没有多大意义...... 如何生成名称?你能提供样本输入和输出吗?为了检查这是否如您所愿,您需要添加几个同名的人;如果所有人都有不同的名字,那么确实c == 0 永远不会是true,并且不会应用第二个排序标准。 @Mike C 好的,我明白了——所以如果我的名单上没有任何人的姓氏相同,那么这段代码除了对姓氏进行排序之外什么都不做?跨度> 【参考方案1】:

考虑如下学生类

public class Student implements Comparable<Student> 
    String name;
    int id;
    double gpa;

    public Student(String name, int id, double gpa) 
        this.name = name;
        this.id = id;
        this.gpa = gpa;
    

    @Override
    public int compareTo(Student o2) 
        int c;
        c = this.name.compareToIgnoreCase(o2.name);
        if (c == 0) 
            c = Double.compare(this.gpa, o2.gpa);
        
        return c;
    


那么下面的main函数给出正确的输出

public static void main(String[] args)

ArrayList<Student> studentList = new ArrayList<Student>();
studentList.add(new Student("Milind", 1, 7.73));
studentList.add(new Student("Milind", 1, 7.70));
studentList.add(new Student("Mike", 1, 7.80));
System.out.println("--Unsorted--");

for (Student student : studentList) 
    System.out.print(student.name + ": ");
    System.out.print(student.gpa);
    System.out.println();

System.out.println();

Collections.sort(studentList);
System.out.println("--Sorted--");

for (Student student : studentList) 
    System.out.print(student.name + ": ");
    System.out.print(student.gpa);
    System.out.println();

输出:

--Unsorted--
Milind: 7.73
Milind: 7.7
Mike: 7.5

--Sorted--
Mike: 7.8
Milind: 7.7
Milind: 7.73

Mike 首先出现,因为它是按字母顺序排列的。并且名字 Milind 与接下来的 2 相同,因此根据 GPA 排序。

应用相同的逻辑,您还将获得基于多个字段的输出。在这种情况下,当 Firstname 相同时 GPA。

【讨论】:

但是,如果所有三个学生的姓氏都不同,这不会按年级排序,对吧?如此处所示,成绩最高的迈克先来,然后是成绩较低的米林德。 比较器仅用于检查名字。所以是的,如果所有 3 名学生的姓氏不同或相同,那没关系,只有名字相同时,输出才会按 GPA 排序。基本上排序将仅按名字进行,如果名字相同,则按 GPA。姓氏可能相同,也可能不一样。 [这是根据我在上面的学生类中编写的比较器] 我正在寻找一种按姓氏和 gpa 排序的解决方案,无论名称是否相同。在您的示例中,它将是 Mike 7.8、Milind、7.73、Milind 7.7。此代码与我提到的示例相同,但还没有到达我需要的地方。 那么你必须改变Student类。在你的学生课上是这样的:@Override public int compareTo(Student o2) int c; c = this.lastname.compareToIgnoreCase(o2.lastname); if (c == 0) c = Double.compare(this.gpa, o2.gpa); 返回 c; 我在回答中粘贴的是基本思想。

以上是关于Java比较器多字段排序不起作用的主要内容,如果未能解决你的问题,请参考以下文章

带有连接表字段排序的 Cakephp 分页不起作用

冒泡排序不起作用

mysql中order by 排序用asc和desc不起作用怎么回事

Codeigniter 日期比较 - 大于或小于日期时间字段不起作用

Java 合并排序不起作用

添加多个字段时,HTML多选下拉菜单Jquery和样式不起作用