0 前言
对 List(次要指 ArrayList)和 Map(次要指 HashMap)的排序是最常见的业务场景,因而,有必要对其进行系统地梳理和学习,本文总结了罕用的排序办法。
1 List 排序
1.1 根本数据类型的排序
a. 数值型数据
// 此处包含本文波及的所有 import,前面的案例不再反复
import org.junit.Test;
import java.text.Collator;
import java.util.*;
import java.util.stream.Collectors;
@Test
public void intTest() {List<Integer> intList = new ArrayList<>();
intList.add(1);
intList.add(5);
intList.add(4);
System.out.println("原始:" + intList);
// 倒置
Collections.reverse(intList);
System.out.println("倒置:" + intList);
// 排序
intList.sort(Comparator.naturalOrder());
System.out.println("正序:" + intList);
intList.sort(Comparator.reverseOrder());
System.out.println("倒序:" + intList);
}
输入后果:
原始:[1, 5, 4]
倒置:[4, 5, 1]
正序:[1, 4, 5]
倒序:[5, 4, 1]
b. 字符型数据
英文字符的排序依照字母表程序,具体操作与数值型排序相似,不再赘述。此处,特地介绍下中文字符的排序,常见的形式是以首个汉字的拼音首字母程序排。
@Test
public void strTest() {List<String> strList = new ArrayList<>();
strList.add("武汉");
strList.add("北京");
strList.add("上海");
System.out.println("原始:" + strList);
// 排序
Collator instance = Collator.getInstance(Locale.CHINA); // 据说遇到生僻字时会有 bug,暂未波及不深究
strList.sort(instance);
System.out.println("正序:" + strList);
strList.sort(instance.reversed());
System.out.println("倒序:" + strList);
}
输入后果:
原始:[武汉, 北京, 上海]
正序:[北京, 上海, 武汉]
倒序:[武汉, 上海, 北京]
1.2 JavaBean 类型的排序
自定义一个 JavaBean:
public class A implements Comparable<A> {
private String name;
private Integer order;
public A(String name, Integer order) {
this.name = name;
this.order = order;
}
public String getName() {return name;}
public void setName(String name) {this.name = name;}
public Integer getOrder() {return order;}
public void setOrder(Integer order) {this.order = order;}
@Override
public String toString() {return "order=" + order+ "name=" + name;}
@Override
public int compareTo(A a) {return this.order.compareTo(a.getOrder());
}
}
对于自定义的 JavaBean 类型,有以下几种常见的排序办法:
@Test
public void objectTest() {List<A> listA = new ArrayList<>();
listA.add(new A("a2", 1));
listA.add(new A("a3", 3));
listA.add(new A("a3", 2));
listA.add(new A("a1", 3));
System.out.println("原始:" + listA);
// 1. 基于 A 的 order 升序排序
// 办法一:list 中的对象 A 实现 Comparable 接口,间接 sort
listA.sort(Comparator.naturalOrder());
System.out.println("1. 基于 order 升序——办法 1:" + listA);
// 办法二:若 A 没有实现 Comparable 接口,应用 Comparator.comparing
listA.sort(Comparator.comparing(A::getOrder));
System.out.println("1. 基于 order 升序——办法 2:" + listA);
// 2. 基于 A 的 order 及 name 的升序排序
List<A> result1 = listA.stream().sorted(Comparator.comparing(A::getOrder).thenComparing(A::getName)).collect(Collectors.toList());
System.out.println("2. 基于 A 的 order 及 name 的升序排序——办法 2 扩大:" + result1);
// 3. 基于 A 的 order 及 name 的降序排序
List<A> result2 = listA.stream().sorted(Comparator.comparing(A::getOrder).thenComparing(A::getName).reversed()).collect(Collectors.toList());
System.out.println("3. 基于 A 的 order 及 name 的降序排序——办法 2 扩大:" + result2);
// 4. 基于 A 的 order 升序以及 name 的降序排序
Comparator<A> comparatorName = (a1, a2) -> -a1.getName().compareTo(a2.getName());
listA.sort(Comparator.comparing(A::getOrder).thenComparing(comparatorName));
System.out.println("4. 基于 A 的 order 升序以及 name 的降序排序——办法 2 扩大:" + listA);
// 办法三:自定义排序
Comparator<A> comparator = (a1, a2) -> {if (a1.getOrder().equals(a2.getOrder())) {return -a1.getName().compareTo(a2.getName());
}
return a1.getOrder().compareTo(a2.getOrder());
};
listA.sort(comparator);
System.out.println("4. 基于 order 升序及 name 降序——办法 3:" + listA);
}
运行后果:
原始:[order=1 name=a2, order=3 name=a3, order=2 name=a3, order=3 name=a1]
1. 基于 order 升序——办法 1:[order=1 name=a2, order=2 name=a3, order=3 name=a3, order=3 name=a1]
1. 基于 order 升序——办法 2:[order=1 name=a2, order=2 name=a3, order=3 name=a3, order=3 name=a1]
2. 基于 A 的 order 及 name 的升序排序——办法 2 扩大:[order=1 name=a2, order=2 name=a3, order=3 name=a1, order=3 name=a3]
3. 基于 A 的 order 及 name 的降序排序——办法 2 扩大:[order=3 name=a3, order=3 name=a1, order=2 name=a3, order=1 name=a2]
4. 基于 A 的 order 升序以及 name 的降序排序——办法 2 扩大:[order=1 name=a2, order=2 name=a3, order=3 name=a3, order=3 name=a1]
4. 基于 order 升序及 name 降序——办法 3:[order=1 name=a2, order=2 name=a3, order=3 name=a3, order=3 name=a1]
2 Map 排序
2.1 根本数据类型的排序
罕用的存储数据的 map 构造是 HashMap,它有着高效的增删改查效率,然而 HashMap 无奈记录数据的程序,因而排序时罕用 linkedHashMap 存储有序数据。
HashMap、LinkedHashMap 的具体介绍参考:
1、https://blog.csdn.net/qq_2876…
2、https://www.cnblogs.com/coder…
@Test
public void test(){Map<String, Double> map = new HashMap<>();
map.put("b", 0.08);
map.put("a", 0.1);
map.put("c", 0.02);
map.put("d", 0.91);
System.out.println("原始:"+map);
Map<String, Double> result = new LinkedHashMap<>();
map.entrySet().stream().sorted(Map.Entry.comparingByKey()).forEachOrdered(e -> result.put(e.getKey(), e.getValue()));
System.out.println("按 key 升序排:"+result);
Map<String, Double> result2 = new LinkedHashMap<>();
map.entrySet().stream().sorted(Map.Entry.comparingByValue()).forEachOrdered(e -> result2.put(e.getKey(), e.getValue()));
System.out.println("按 value 升序排:"+result2);
}
运行后果:
原始:{a=0.1, b=0.08, c=0.02, d=0.91}
按 key 升序排:{a=0.1, b=0.08, c=0.02, d=0.91}
按 value 升序排:{c=0.02, b=0.08, a=0.1, d=0.91}
逆序能够在 comparingByKey 或 comparingByValue 后增加 reversed,将排序办法封装如下:
/*
* 基于 value 排序
* @param isReverse 示意是否逆序排
* @return
*/
public <K, V extends Comparable<? super V>> Map<K, V> sortByValue(Map<K, V> map, boolean isReverse) {Map<K, V> result = new LinkedHashMap<>();
if (isReverse) {map.entrySet().stream().sorted(Map.Entry.<K, V>comparingByValue().reversed()).forEachOrdered(e -> result.put(e.getKey(), e.getValue()));
} else {map.entrySet().stream().sorted(Map.Entry.<K, V>comparingByValue()).forEachOrdered(e -> result.put(e.getKey(), e.getValue()));
}
return result;
}
/*
* 基于 key 排序
* @param isReverse 示意是否逆序排
* @return
*/
public <K extends Comparable<? super K>, V> Map<K, V> sortByKey(Map<K, V> map, boolean isReverse) {Map<K, V> result = new LinkedHashMap<>();
if (isReverse) {map.entrySet().stream().sorted(Map.Entry.<K, V>comparingByKey().reversed()).forEachOrdered(e -> result.put(e.getKey(), e.getValue()));
} else {map.entrySet().stream().sorted(Map.Entry.<K, V>comparingByKey()).forEachOrdered(e -> result.put(e.getKey(), e.getValue()));
}
return result;
}
除了 HashMap 和 LinkedHashMap 之外,还有一种不须要额定的排序操作,数据存储时就是有序的构造,称之为 TreeMap。
TreeMap 的具体介绍参考:
1、https://blog.csdn.net/chenssy…
2、https://www.liaoxuefeng.com/w…
其应用办法如下:
@Test
public void treeMapTest(){TreeMap<String,Double> map = new TreeMap<>();
map.put("b", 0.08);
map.put("a", 0.1);
map.put("c", 0.02);
System.out.println("默认按 key 正序:"+map);
TreeMap<String,Double> map2 = new TreeMap<>(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {return -o1.compareTo(o2);
}
});
map2.put("b", 0.08);
map2.put("a", 0.1);
map2.put("c", 0.02);
System.out.println("自定义按 key 逆序:"+map2);
}
留神:TreeMap 仅反对对 key 排序,如需对 value 排序,则须要转换成 list 之后再 sort,不再赘述。
2.2 JavaBean 类型的排序
常见的场景是:map 的 value 存储的 JavaBean,须要依照 JavaBean 中的字段排序。
比方依照 A 的 order 升序及 name 的降序排序,代码如下:
@Test
public void objectTest(){Map<String, A> map = new HashMap<>();
map.put("b", new A("a2", 1));
map.put("a", new A("a3", 3));
map.put("c", new A("a3", 2));
map.put("d", new A("a1", 3));
Map<String, A> result = new LinkedHashMap<>();
Comparator<Map.Entry<String, A>> comparator = (c1, c2) -> {A a1=c1.getValue();
A a2=c2.getValue();
if (a1.getOrder().equals(a2.getOrder())) {return -a1.getName().compareTo(a2.getName());
}
return a1.getOrder().compareTo(a2.getOrder());
};
map.entrySet().stream().sorted(comparator).forEachOrdered(e -> result.put(e.getKey(), e.getValue()));
System.out.println("按 value 升序排:"+result);
}
运行后果:
依照 value 中的 order 升序及 name 的降序排序 {b=order=1 name=a2, c=order=2 name=a3, a=order=3 name=a3, d=order=3 name=a1}