一、对int、float、String类型进行降序输出
TreeSet在默认的情况下对int、float等基本数据以及String类型的排序升序排序的,但如果我们想对这类数据执行降序排序怎么办呢?别怕,TreeSet提供了个descendingSet();来满足我们这一需求,下面分别以int类型和String类型的数据进行演示如何在代码中使用descendingSet()来实现降序排序。
1、存储int类型时
public static void main(String[] args) {
TreeSet<Integer> intSet = new TreeSet<>();
intSet.add(23);
intSet.add(68);
intSet.add(33);
intSet.add(15);
intSet.add(22);
intSet.add(53);
System.out.println("整型在TreeSet中自然排序后输出:");
for (int x : intSet) {
System.out.printf("%d ", x);
}
System.out.println();
TreeSet<Integer> reIntSet = new TreeSet<Integer>();
reIntSet = (TreeSet) intSet.descendingSet();
System.out.println("整型降序排序后输出:");
//此处也可以直接遍历intSet.descendingSet()结果是相同的
//即for (int x : intSet.descendingSet())
for (int x : reIntSet) {
System.out.printf("%d ", x);
}
}
输出为:
2、存储String类型时
public static void main(String[] args) {
TreeSet<String> stringSet = new TreeSet<>();
stringSet.add("makor");
stringSet.add("jack");
stringSet.add("Boolo");
stringSet.add("xiaodong");
stringSet.add("3huan");
stringSet.add("3ajk");
System.out.println("String在TreeSet中自然排序后输出:");
for (String s : stringSet) {
System.out.printf("%s ", s);
}
System.out.println("\nString降序后输出:");
for (String s : stringSet.descendingSet()) {
System.out.printf("%s ", s);
}
}
输出为:
二、对自定义对象进行排序
有时候,我们会有对自定义类进行排序的需求,这个时候就要用到我们的Comparator接口和Comparable接口了。
1、通过比较器Comparator来实现(让容器自身具有比较性)
首先我们创建一个自定义对象User:
static class User {
int age;
String name;
User(){}
User(int age, String name) {
this.age = age;
this.name = name;
}
public String toString(){
return "姓名:" + name + ", 年龄:" + age;
}
//根据age来升序排序的比较器
static class UserCompForAge implements Comparator {
@Override
public int compare(Object o1, Object o2) {
User u1 = (User)o1;
User u2 = (User)o2;
// 注意:此处用自定义类的age来实施比较,
// 所以age值相同的元素不能被加入成功
return u1.age - u2.age;
}
}
//根据name来降序排序的比较器
static class UserCompForName implements Comparator {
@Override
public int compare(Object o1, Object o2) {
User u1 = (User)o1;
User u2 = (User)o2;
// 注意:此处用自定义类的name来实施比较,
// 所以name值相同的元素后面不能被加入成功
return u2.name.compareTo(u1.name);
}
}
//根据age降序,若age相同则根据name来升序排序的比较器
//若age和name都相同,则加入不成功
static class UserCompForAgeAndName implements Comparator {
@Override
public int compare(Object o1, Object o2) {
User u1 = (User)o1;
User u2 = (User)o2;
if (u1.age == u2.age) return u1.name.compareTo(u2.name);
return u2.age - u1.age;
}
}
}
然后编写测试方法,此处我们传入的是根据age升序来排序的比较器
(TreeSet<User> userSet = new TreeSet<>(new User.UserCompForAge());):
public static void main(String[] args) {
//此处传入的是根据age来排序的,所以后面加入的user中,
//如果年龄已经出现过了,就加入不了集合中
TreeSet<User> userSet = new TreeSet<>(new User.UserCompForAge());
userSet.add(new User(18, "zhang"));
userSet.add(new User(58, "li"));
userSet.add(new User(28, "wang"));
userSet.add(new User(28, "wang"));
userSet.add(new User(68, "wang"));
userSet.add(new User(18, "qian"));
userSet.add(new User(18, "wu"));
for (User u : userSet) {
System.out.println(u.toString());
}
}
运行结果如下:
修改测试代码,将传入的比较器换成根据name降序排序的比较器,只需要修改下面这行代码:
TreeSet<User> userSet = new TreeSet<>(new User.UserCompForName());具体如下:
public static void main(String[] args) {
//此处传入的是根据name来排序的,所以后面加入的user中,
// 如果name已经出现过了,就加入不了集合中
TreeSet<User> userSet = new TreeSet<>(new User.UserCompForName());
userSet.add(new User(18, "zhang"));
userSet.add(new User(58, "li"));
userSet.add(new User(28, "wang"));
userSet.add(new User(28, "wang"));
userSet.add(new User(68, "wang"));
userSet.add(new User(18, "qian"));
userSet.add(new User(18, "wu"));
for (User u : userSet) {
System.out.println(u.toString());
}
}
运行结果如下:
可以发现,TreeSet会根据传入的比较器来去重(即:如果向集合中加入一个元素,它会先将该元素中的一个属性与集合中已有的元素的这个属性进行比较,如果该属性的值已经出现过了,那么这个元素将不能加入集合。比较的那个属性是你传入的比较器中来指定排序规则的那个属性)。
当然,我们也可以通过修改比较器中的compare方法,让元素的排序规则由多个属性的值来决定,那么只要这些属性的值中有一个不同,那么就可以加入成功,但如果都相同的话,还是不能加入成功。测试代码只修改了下面这一行
TreeSet<User> userSet = new TreeSet<>(new User.UserCompForAgeAndName());
具体如下:
public static void main(String[] args) {
//此处传入的是根据age,name来排序的,所以后面加入的user中,
// 如果集合中有元素的age和name值都与要加入的元素的值相同的话,就加入不了集合中
TreeSet<User> userSet = new TreeSet<>(new User.UserCompForAgeAndName());
userSet.add(new User(18, "zhang"));
userSet.add(new User(58, "li"));
userSet.add(new User(28, "wang"));
userSet.add(new User(28, "wang"));
userSet.add(new User(68, "wang"));
userSet.add(new User(18, "qian"));
userSet.add(new User(18, "wu"));
for (User u : userSet) {
System.out.println(u.toString());
}
}
输出如下,我们可以看出,代码中先后加入了两个age=28, name=“wang”的元素,但只成功加入了第一个。而单独的name或age相同的元素,我们都能加入多个。
2、自定义类实现Comparable接口(让元素自身具有比较性)
首先,我们编写我们的测试方法如下:
public static void main(String[] args) {
TreeSet<User> userSet = new TreeSet<>();
userSet.add(new User(18, "zhang"));
userSet.add(new User(58, "li"));
userSet.add(new User(28, "wang"));
userSet.add(new User(68, "wang"));
userSet.add(new User(18, "qian"));
userSet.add(new User(18, "wu"));
for (User u : userSet) {
System.out.println(u.toString());
}
}
然后编写我们的User类,此处实现了Comparable接口,需要重写compareTo方法,然后在该方法中实现我们自定义的比较逻辑。同样的,集合中不能有相同的决定我们排序规则的属性值。具体代码如下:
static class User implements Comparable{
int age;
String name;
User(){}
User(int age, String name) {
this.age = age;
this.name = name;
}
public String toString(){
return "姓名:" + name + ", 年龄:" + age;
}
@Override
//根据age升序,age相同的根据name降序排序,重复的age和name会加入集合失败
public int compareTo(Object o) {
User u = (User) o;
if (age == u.age) return u.name.compareTo(name);
return age - u.age;
}
// @Override
// //根据name降序排序,重复的name会加入集合失败
// public int compareTo(Object o) {
// User u = (User) o;
// return u.name.compareTo(name);
// }
// @Override
// //根据age升序排序,重复的age会加入集合失败
// public int compareTo(Object o) {
// User u = (User) o;
// return age - u.age;
// }
}
运行结果如下:
此处我们使用的是根据age升序,age相同的根据name降序来排序的,所以测试代码中add了两个age=28, name="wang"的对象,可加入集合的只有一个。当然也可以根据单独的age或那么来制定排序规则,实现方法如User类中的注释代码所示。运行结果与定义Comparator类的类似,此处就不重复演示了。有兴趣的读者可以自己运行一下以增加理解和印象。