面试题目——集合List根据其中的字段进行排序


今天突然被同事问道:把list集合按照其中一个字段进行降序或者升序排列;
第一反应是可以在查SQL的时候用order by xxx desc(asc)就行了呀,实则不然,在做项目的时候有很多地方不仅仅是这样就行了

然后查了一些资料,有两种写法,自己在这里做一个记录:


首先看第一种 实现 Comparable 接口,实现 compareTo() 方法

最近用java抓取数据的时候,遇到了需要对拿到的List集合按照多个字段进行排序。
首先得让排序的实体类实现Comparable类并且重写它的compareTo方法,在compareTo中你可以自定义排序的规则。
如果前者大于后者,则返回1,若果相等则返回0,若果前者小于后者,则返回-1;String字符串比较的时候也会经常用到这个compareTo方法,查看String类,可以看到它也实现了Comparable类。

新建一个User类:按照id升序,age降序来排序。

import lombok.AllArgsConstructor;
import lombok.Data;

import java.io.Serializable;
@Data
@AllArgsConstructor
public class User implements Comparable<User> ,Serializable {

    private static final long serialVersionUID = 7845798963273695832L;

    private int id;
    private int age;
    private String name;

    /*
    * 按照id升序排列,按照age降序排列
    * */
    @Override
    public int compareTo(User o) {
        if (this.getId() > o.getId()) {
            return 1;
        } else if (this.getId() < o.getId()) {
            return -1;
        } else {
            if (this.getAge() > o.getAge()) {
                return -1;
            } else {
                return 1;
            }

        }
    }
}

再建一个Junit测试类 Collections.sort(list);

 @Test
    public void test2(){
        List<User> list = new ArrayList<>();
        list.add(new User(1, 1, "A"));
        list.add(new User(3, 2, "B"));
        list.add(new User(3, 3, "C"));
        list.add(new User(5, 4, "D"));
        list.add(new User(5, 5, "E"));
        System.out.println("排序前:"+list);
        for (User user : list) {
            System.out.println("id:"+user.getId()+" age:"+user.getAge()+" name:"+user.getName());
        }
        System.out.println("排序后:");
        // 如果对象实现了 Comparable 接口并且重写了compareTo 方法,我们也可以使用这种方式进行排序
        // list.stream().sorted().forEach(System.out::println);

        //id升序,age降序
        Collections.sort(list);
        for (User user1 : list) {
            System.out.println("id:"+user1.getId()+" age:"+user1.getAge()+" name:"+user1.getName());
        }
    }

排序结果:

id:1 age:1 name:A
id:3 age:2 name:B
id:3 age:3 name:C
id:5 age:4 name:D
id:5 age:5 name:E
排序后:
id:1 age:1 name:A
id:3 age:3 name:C
id:3 age:2 name:B
id:5 age:5 name:E
id:5 age:4 name:D

使用 Stream 流进行排序

@Data
@AllArgsConstructor
public class UserDto {
    private int id;
    private int age;
    private String name;

    public static void main(String[] args) {
        List<UserDto> list = new ArrayList<>();
        list.add(new UserDto(1, 1, "A"));
        list.add(new UserDto(3, 5, "B"));
        list.add(new UserDto(3, 3, "C"));
        list.add(new UserDto(5, 4, "D"));
        list.add(new UserDto(5, 5, "E"));

        // 根据 id 升序排序
        list.stream().sorted(Comparator.comparing(UserDto::getId)).forEach(System.out::println);

        System.out.println("--------根据 age 降序排序----------------");
        // 根据 age 降序排序  reversed就是将顺序倒过来
        list.stream().sorted(Comparator.comparing(UserDto::getAge).reversed()).forEach(System.out::println);

        // 根据 id 升序,如果id相同的话再根据 age 升序排序 (二级排序就是当一级排序的两个元素相等的时候,再用二级排序进行比较)
        System.out.println("----根据 id 升序,如果id相同的话再根据 age 升序排序------");
        list.stream().sorted(Comparator.comparing(UserDto::getId).thenComparing(UserDto::getAge))
                .forEach(System.out::println);

        /**
         * 按照 id 升序排序, 按照 age 降序排序
         */
        System.out.println("-----按照 id 升序排序, 按照 age 降序排序----");
        list.stream().sorted((p1, p2) -> {
            if (p1.getId() > p2.getId()) {
                return 1;
            } else if (p1.getId() < p1.getId()) {
                return -1;
            } else {
                if (p1.getAge() > p2.getAge()) {
                    return -1;
                } else {
                    return 1;
                }
            }
        }).forEach(System.out::println);
    }
}

第二种写法 实现 Comparator 接口,重写 Compare()方法

情景:现在有一个List,需要对病人每一次的体检记录(Quota)按照日期进行降序排序(即近期放在最前面)
Collectionssort()方法默认是升序排列,如果需要降序排列时就需要重写compare方法

首先放出compare的注释

 * @param o1 the first object to be compared.
     * @param o2 the second object to be compared.
     * @return a negative integer, zero, or a positive integer as the
     *         first argument is less than, equal to, or greater than the
     *         second.
     * @throws NullPointerException if an argument is null and this
     *         comparator does not permit null arguments
     * @throws ClassCastException if the arguments' types prevent them from
     *         being compared by this comparator.
     */
    int compare(T o1, T o2);

也就是说默认o1和o2比较,如果o1-o2返回负数,则把o1放在o2前面。(升序)

Collections.sort(list, new Comparator<Integer>() {
            public int compare(Integer o1, Integer o2) {
                return o1 - o2;//注意这一行代码
            }
        });

可我现在要实现降序,那么思路应该是

Collections.sort(list, new Comparator<Integer>() {
            public int compare(Integer o1, Integer o2) {
                return o2 - o1;//注意这一行代码
            }
        });

解释完compare方法,下面是该情景解决方案:

Quota实体类

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.io.Serializable;

@Data
@Slf4j
@AllArgsConstructor
public class Quota implements Serializable {

    private static final long serialVersionUID = -3112288909486144393L;

    private String date;

}
@Test
    public void test3(){
        List<Quota> list = new ArrayList<>();
        list.add(new Quota("2020-07-01"));
        list.add(new Quota("2020-07-09"));
        list.add(new Quota("2020-05-06"));
        list.add(new Quota("2020-06-06"));
        list.add(new Quota("2020-03-07"));
        //Collections的sort方法默认是升序排列,如果需要降序排列时就需要重写compare方法
        Collections.sort(list, new Comparator<Quota>() {
            @Override
            public int compare(Quota o1, Quota o2) {
                SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
                try {
                    //获取体检日期,并把其类型由String转化成Date,便于比较
                    Date dt1 = format.parse(o1.getDate());
                    Date dt2 = format.parse(o2.getDate());
                    //一下代码决定按日期降序排序,若将return ”-1“与"1"互换,即可实现降序
                    //getTime方法返回一个整数值,这个整数值代表了从1970年1月1日开始计算到date对象中的时间之间的毫秒数
                    if(dt1.getTime() > dt2.getTime()){
                        return -1;
                    }else if(dt1.getTime() < dt2.getTime()){
                        return  1;
                    }else {
                        return 0;
                    }

                } catch (ParseException e) {
                    e.printStackTrace();
                }
                return 0;
            }

        });
        for (Quota quota : list) {
            System.out.println("date:"+quota.getDate());
        }

    }

执行结果

date:2020-07-09
date:2020-07-01
date:2020-06-06
date:2020-05-06
date:2020-03-07

上面第二种方法还有一种写法: list.sort();

list.sort(new Comparator<Quota>() {
    @Override
    public int compare(Quota o1, Quota o2) {
         SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
                    //获取体检日期,并把其类型由String转成Date,便于比较。
                    Date dt1 = format.parse(o1.getDate());
                    Date dt2 = format.parse(o2.getDate());

                    //以下代码决定按日期降序排序,若将return“-1”与“1”互换,即可实现升序。
                    //getTime 方法返回一个整数值,这个整数代表了从 1970 年 1 月 1 日开始计算到 Date 对象中的时间之间的毫秒数。
                    if (dt1.getTime() > dt2.getTime()) {
                        return -1;
                    } else if (dt1.getTime() < dt2.getTime()) {
                        return 1;
                    } else {
                        return 0;
                    }
    }
});

注意:
一个是:Collections.sort(list);
另一个是:list.sort();

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值