一、从TreeMap说起
TreeMap中自带了一个比较器comparator,所以它有默认的排序方法
我们先来看个小例子:
public static void main(String[] args) {
Map<String, Integer> map = new TreeMap<>();
map.put("ZhangSan", 35);
map.put("LiSi", 25);
map.put("WangWu", 35);
map.put("XiaoHong", 15);
map.put("YaSe", 27);
for (String s : map.keySet()) {
System.out.println("姓名:"+s+", 年龄:"+map.get(s));
}
}
从下图中可以看到运行的结果是按照Key值升序来排的:
因为TreeMap提供了将比较器作为传参的方式传入TreeMap中的构造方法,所以我们在创建TreeMap的时候也可以通过传参来定制TreeMap的排序规则。
//下面这个是TreeMap中传入比较器的构造方法
public TreeMap(Comparator<? super K> comparator) {
this.comparator = comparator;
}
我们继续使用上面的那个例子并修改代码,在创建TreeMap的时候传入一个比较器,使得其中的map中的元素按照健值降序排序并输出:
public static void main(String[] args) {
Map<String, Integer> map = new TreeMap<>(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o2.compareTo(o1);
}
});
map.put("ZhangSan", 35);
map.put("LiSi", 25);
map.put("WangWu", 35);
map.put("XiaoHong", 15);
map.put("YaSe", 27);
for (String s : map.keySet()) {
System.out.println("姓名:"+s+", 年龄:"+map.get(s));
}
}
得到如下结果:
二、按照value的值来进行排序
细心的小伙伴们可能会发现,我们刚才都是使用key值来排序的,如果想要使用value来进行排序,又应该怎么设置呢?
这个时候我们要使用到Map类中的一个内部接口Entry<k,v>,可以通过将map中的键值对转换为Entry类型,然后放入到Collection类型的容器中,再通过在Collections.sort()方法中自定义比较器来定制排序。首先我们使用这个方法来实现以下上述的例子(为了和TreeMap中自带的比较器区分,我们使用HashMap来实现)
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>();
map.put("ZhangSan", 35);
map.put("LiSi", 25);
map.put("WangWu", 35);
map.put("XiaoHong", 15);
map.put("YaSe", 27);
System.out.println("排序前:");
for (String s : map.keySet()) {
System.out.println("姓名:"+s+", 年龄:"+map.get(s));
}
//此处其实通过了中介List来实现排序的
List<Map.Entry<String, Integer>> list = new LinkedList<>(map.entrySet());
Collections.sort(list, new Comparator<Map.Entry<String, Integer>>() {
@Override
public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
return o1.getKey().compareTo(o2.getKey());
}
});
System.out.println("排序后:");
for (Map.Entry<String, Integer> entry : list) {
System.out.println("姓名:"+entry.getKey()+", 年龄:"+entry.getValue());
}
}
输出结果如下:
当然,你也可以通过修改 比较器的逻辑来修改排序方式。
使用Entry的方式来进行排序的话,不仅仅可以通过键值来排序,也可以通过值来排序:
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>();
map.put("ZhangSan", 35);
map.put("LiSi", 25);
map.put("WangWu", 35);
map.put("XiaoHong", 15);
map.put("YaSe", 27);
System.out.println("排序前:");
for (String s : map.keySet()) {
System.out.println("姓名:"+s+", 年龄:"+map.get(s));
}
//此处其实通过了中介List来实现排序的
List<Map.Entry<String, Integer>> list = new LinkedList<>(map.entrySet());
Collections.sort(list, new Comparator<Map.Entry<String, Integer>>() {
@Override
public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
//年龄相同时,按照姓名降序排序
if (o1.getValue() == o2.getValue()) {
return o2.getKey().compareTo(o1.getKey());
}
//按照年龄升序排序
return o1.getValue() - o2.getValue();
}
});
System.out.println("排序后:");
for (Map.Entry<String, Integer> entry : list) {
System.out.println("姓名:"+entry.getKey()+", 年龄:"+entry.getValue());
}
}
上面的例子不仅定制了按照年龄升序来排序,同时在年龄相等的情况下,会按照姓名降序的方式来排序。具体的运行结果如下:
三、做个小补充
在【二】中,我们使用了Entry的方式来给Map定制排序,其中使用的是HashMap。需要注意的是,HashMap中并没有定义比较器,所以它是不能够自动安装key来排序的。那么如果在不使用Entry的前提下,有没有什么方法可以给HashMap安装key排序呢?
答案是有的,可以通过下面的例子来看看:
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>();
map.put("ZhangSan", 35);
map.put("LiSi", 25);
map.put("WangWu", 35);
map.put("XiaoHong", 15);
map.put("YaSe", 27);
System.out.println("排序前:");
for (String s : map.keySet()) {
System.out.println("姓名:"+s+", 年龄:"+map.get(s));
}
System.out.println("排序后:");
List<String> listKey = new LinkedList<>(map.keySet());
//此处如果不传入自己定制的比价器,即Collections.sort(listKey);
//那么结果输出结果是按照key升序排序的
Collections.sort(listKey, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o2.compareTo(o1);
}
});
for (String s : listKey) {
System.out.println("姓名:"+s+", 年龄:"+map.get(s));
}
}
运行结果如下:
其实,究其本质,该例子和【二】中一样都是借用了Collection来进行排序,在平时的刷题中,如果可以灵活的去定制一个比较器,有时候会让你事半功倍,少写很多代码。