【重要】经验之谈:
在使用Java自带的排序函数时,往往需要根据自己的需求,自定义比较器
。那么问题来了,比较器
是怎么确定按“升序”排序还是“降序”排序的呢?
实现Comparaotor接口,必须实现下面这个函数:
@Override public int compare(CommentVo v1, CommentVo v2) { return v1-v2; //升序 return v2-v1; //降序 }
其实,是根据返回值判断的,如果返回值为1(即>0),则交换v1、v2的位置,否则不换。
例如:
v1=5, v2=6;
- return v1-v2; 5-6 返回值为-1 (<0),不交换,顺序为v1、v2,结果为升序。
- return v2-v1; 6-5 返回值为1 (>0),交换,交换后顺序为:v2、v1,结果为降序。
Java排序器之升序or降序
一、如何确定升序还是降序?
Java中在进行对象排序时,设计的排序器经常会对两个对象按照一定的排序规则排序,可如何确定排序规则是升序还是降序呢?笔者整理了一个简单的方法来确定排序规则。
o1和o2是需要表示排序的两个对象,假定比较前的默认顺序为 [o1, o2],是升序还是降序暂时不做考虑,完全根据返回值结果表示是否需要调整当前的排序顺序,便能够理解排序的真正逻辑,以确定是升序排序还是降序排序。
假设我们的比较器规则如下:o1对象作为比较的前者,o2对象作为排序的后者,即比较方式为 [o1 - o2]或者 [o1.compareTo(o2)]。
class ComparatorByAge implements Comparator { // 根据年龄和姓名排序 @Override public int compare(Object o1, Object o2) { Person p1 = (Person) o1; Person p2 = (Person) o2; int tmp = p1.getAge() - p2.getAge(); return tmp == 0 ? p1.getName().compareTo(p2.getName()) : tmp; } }
升序规则:
- o1 > o2,返回正数,true,表示需要调整顺序,升序。
- o1 < o2,返回负数,false,表示不需要调整顺序,升序。
降序规则:
- o1 > o2,返回负数,false,表示不需要调整顺序,降序。
- o1 < o2,返回正数,true,表示需要调整顺序,降序。
不排序规则:
- o1 = o2,返回0,按当前顺序即可,或者比较其他参数。
二、实际用例
Person 是定义的需要排序的对象,包括年龄和姓名两个字段。
class Person implements Comparable{ private String name; private int age; // 重写toString()方法,输出对象时输出格式为:name:age @Override public String toString() { return name+ ":" + age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Person(String name, int age) { super(); this.name = name; this.age = age; } // Person自带的排序规则 @Override public int compareTo(Object o) { Person p = (Person) o; // 根据年龄进行排序 int temp = this.age - p.age; return temp == 0 ? this.name.compareTo(p.name):temp; } }
排序规则一:定义升序排序器,先按年龄升序,再按姓名首字母升序。
- 比如 o1对象为 (zhangshan:20) ,o2 对象为 (wangwu:21) ,默认排序 [o1, o2],由于 o1.age < o2.age,比较结果返回负数,false,表示不需要调整规则,按年龄升序排序,最终排序结果为 [zhangshan:20, wangwu:21]。
- 比如 o1 对象为 (zhangshan:20) ,o2对象为 (lisi:20),默认排序 [o1,o2],由于 o1.age = o2.age,比较结果为0,不按年龄排序,进一步比较name,由于 o1.name > o2.name,返回 true,调整排序规则,即按字母升序排序,最终排序结果为 [lisi:20, zhangshan:20]。
/** * 自定义升序排序器 * 升序:先按年龄升序,再按姓名首字母升序 */ class ComparatorByAge implements Comparator { // 根据年龄排序 @Override public int compare(Object o1, Object o2) { Person p1 = (Person) o1; Person p2 = (Person) o2; int tmp = p1.getAge() - p2.getAge(); return tmp == 0 ? p1.getName().compareTo(p2.getName()) : tmp; } }
排序规则二:定义降序排序器,先按年龄降序,再按姓名首字母降序。和升序的唯一区别就是返回结果的参数前添加了一个负号。
/** * 自定义降序排序器 * 降序:先按年龄降序,再按姓名首字母降序 */ class ComparatorByAge2 implements Comparator { // 根据年龄排序 @Override public int compare(Object o1, Object o2) { Person p1 = (Person) o1; Person p2 = (Person) o2; int tmp = p1.getAge() - p2.getAge(); return tmp == 0 ? -(p1.getName().compareTo(p2.getName())) : -tmp; } }
排序 main() 方法,查看两种排序器的排序结果。
public class TreeSetDemo { public static void main(String[] args) { TreeSet<Person> ts = new TreeSet(new ComparatorByAge()); ts.add(new Person("zhangsan", 20)); ts.add(new Person("wangwu", 21)); ts.add(new Person("lisi", 20)); ts.add(new Person("zhouqi", 29)); ts.add(new Person("zhaoliu", 28)); for (Person person : ts) { System.out.println(person); } /* 结果输出 lisi:20 zhangsan:20 wangwu:21 zhaoliu:28 zhouqi:29 */ ts = new TreeSet(new ComparatorByAge2()); ts.add(new Person("zhangsan", 20)); ts.add(new Person("wangwu", 21)); ts.add(new Person("lisi", 20)); ts.add(new Person("zhouqi", 29)); ts.add(new Person("zhaoliu", 28)); for (Person person : ts) { System.out.println(person); } /* 结果输出 zhouqi:29 zhaoliu:28 wangwu:21 zhangsan:20 lisi:20 */ } }
参考: