java有一个比较器接口Comparator,里面有一个compare方法。
比较函数有两个参数a,b;返回a-b就是升序,返回b-a就是降序。不过最好用比较,不要用相减。
使用场景:
- Arrays里面有一个sort(T[],Comparator)可以根据比较器对数组的数据进行排序。排序二维数组是最好用的选择。
例如每个人都有身高和体重[h,w],有n个人,就可以弄成二维数组。然后按照身高或者体重进行排序。 - 数组降序排序也要使用比较器,根据比较器进行排序。
- 优先级队列里面也要使用比较器。
//points是一个n*2的数组。
public static void findMinArrowShots(int[][] points) {
//lambda写法,比较简洁,不过存在溢出危险,最好使用比较,升序,把后面改成b[0]-a[0]就是降序
//这里的a,b都是一维数组,因为points是二维数组
Arrays.sort(points,(a,b)->(a[0]-b[0]));
//lambda写法,该方式不会溢出,虽然写多一点,推荐该方式,升序,把判断的>,<转一下就是降序
Arrays.sort(points,(a,b)->{
if(a[0]>b[0]){
return 1;
}else if(a[0]<b[0]){
return -1;
}else{
return 0;
}
});
/**
* 匿名内部类写法
* 该方式会直接获取points里面的节点
*/
Arrays.sort(points, new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
/**
这个是按points[i][0]从小到大排序,如果要从大到小,只需要把判断的符合改一下
* 这里的每个参数就是二维数组里面的一个一维数组
* o1[]就是points[i]
*/
if(o1[0]>o2[0]){
return 1;
}else if(o1[0]<o2[0]){
return -1;
}else{
return 0;
}
}
});
/**
* 这是先创建比较器,然后再将比较器对象作为参数放到函数中
* 这里能使用points是因为在points的作用域里面
*/
Comparator comparator=new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
if(points[o1][0]>points[o2][0]){
return 1;
}else if(points[o1][0]<points[o2][0]){
return -1;
}else{
return 0;
}
}
};
PriorityQueue queue1=new PriorityQueue(comparator);
for(int i=0;i<points.length;i++){
queue1.offer(i);
}
/**
* lambda表达式写法
* 个人比较喜欢这种。
*/
PriorityQueue<Integer> queue=new PriorityQueue<>((a, b)-> {
if(points[a][0]>points[b][0]){//
return 1;
}else if(points[a][0]<points[b][0]){
return -1;
}
return 0;
});
for(int i=0;i<points.length;i++){
queue.offer(i);
}
}
lambda写法
最近学了lambda表达式的写法,真是太酷啦,代码简洁多了。不过注意,这种写法只支持对象。
如果只是简单的比较逻辑,可以用Comparator.comparing(类名::获取字段方法名),这个是按照该字段升序排序比较器
Comparator.comparing(类名::获取字段方法名,Comparator.reverseOrder()),这个是按照该字段降序排序比较器
Comparator.comparing(类名::获取字段方法名1,Comparator.reverseOrder()).thenComparing(类名::获取字段方法名2),这个是按照字段1降序,如果字段1一样,再按照字段2升序排序比较器
import java.util.*;
import java.util.stream.Collectors;
/**
* @ClassName: Test
* @Author: zengjingchao
* @Date: 2023/6/1 14:18
* @Description:
**/
public class Test {
public static void main(String[] args) throws InterruptedException {
List<TTT> list=new ArrayList<>();
list.add(new TTT(new Date()));
Thread.sleep(1000);
list.add(new TTT(new Date()));
list.add(new TTT(new Date()));
Thread.sleep(1000);
list.add(new TTT(new Date()));
list.add(new TTT(new Date()));
//最大值,默认就是按照比较器的比较逻辑,取最后一个
Optional<TTT> max = list.stream().max(Comparator.comparing(TTT::getA));
System.out.println(max.get().getA());
System.out.println("----------");
for(TTT ttt:list){
System.out.println(ttt.getA());
}
System.out.println("---------");
//降序,因为在比较器加多了一个参数Comparator.reverseOrder(),代表反转,推荐这种写法
List<TTT> collect = list.stream().sorted(Comparator.comparing(TTT::getA, Comparator.reverseOrder())).collect(Collectors.toList());
for(TTT ttt:collect){
System.out.println(ttt.getA());
}
//按照a时间降序,如果时间相同,则按照b升序排,这个是后面加上的,没有跑
collect = list.stream().sorted(Comparator.comparing(TTT::getA, Comparator.reverseOrder()).thenComparing(TTT::getB)).collect(Collectors.toList());
for(TTT ttt:collect){
System.out.println(ttt.getA());
}
}
}
//实体类
public class TTT {
private Date a;
public TTT(Date a) {
this.a = a;
}
public Date getA() {
return a;
}
public void setA(Date a) {
this.a = a;
}
}