Map集合(List<Map>)或者实体类集合(List<Entity>)该如何排序?

如果你向神求助,说明你相信了神的力量;如果神没有帮助你,说明神相信了你的力量。

前言

排序”这两个字想必大家如果学过算法的话恐怕都不会陌生。但是我们在算法的学习中往往都是用一个整数数组来进行排序,而在实际工作中,我们往往碰到的都是实体类集合或者Map集合的形式。那么,在这种情况下,我们该如何进行排序呢?

前期准备

实体类

我们先来准备一个实体类,待会用于生成实体类集合再排序:

package listsort;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

/**
 * @ClassName Entity
 * @Description 实体类 - 人类
 * @Author 古阙月
 * @Date 2020/12/27
 * @Version 1.0
 */
//lombok插件的注解
@Data // 若未使用lombok插件,请自行生成getter、setter以及toString方法
@AllArgsConstructor // 若未使用lombok插件,请自行生成有参构造方法
@NoArgsConstructor // 若未使用lombok插件,请自行生成无参构造方法
@Accessors(chain = true) // 开启链式编程
public class Person {

    /**
     * 姓名
     */
    private String name;

    /**
     * 年龄
     */
    private int age;
}

生成集合工具类

再来一个可以批量生成集合的工具类:

package listsort;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @ClassName GainList
 * @Description 获取集合的工具类
 * @Author 古阙月
 * @Date 2020/12/27 23:43
 * @Version 1.0
 */
public class GainList {

    /**
     * 随机生成包含num个map的List集合
     * @param num
     * @return
     */
    public static List<Map> getMapList(int num) {

        List<Map> mapList = new ArrayList<>();
        for (int i = 0; i < num; i++) {

            // 随机生成 0-100 直接的整数
            int j = (int) (Math.random() * 101);

            Map map = new HashMap();
            map.put("name", "李华"+j);
            map.put("age", j);
            mapList.add(map);
        }

        return mapList;
    }

    /**
     * 随机生成包含num个人类的List集合
     * @param num
     * @return
     */
    public static List<Person> getPersonList(int num) {

        List<Person> personList = new ArrayList<>();
        for (int i = 0; i < num; i++) {

            // 随机生成 0-100 直接的整数
            int j = (int) (Math.random() * 101);

            Person person = new Person();
            person.setName("李华"+j);
            person.setAge(j);
            personList.add(person);
        }

        return personList;
    }
}

方式一

实体类集合排序

如果让你们将一个包含实体类人类的集合按照年龄升序排序,你们会怎么做?

可能很多小伙伴会像下面的代码一样先得到一个年龄升序的数组(反正我之前就是这么做的,结果挨批了),然后再根据这个年龄数组将集合中的实体类一个个抽出来:

package listsort;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @ClassName ListEntitySort
 * @Description List<entity> 排序 - 老方法
 * @Author 古阙月
 * @Date 2020/12/25
 * @Version 1.0
 */
public class ListEntitySort {
    public static void main(String[] args) {

        // 用于得到排序后返回的list
        List<Person> sortList = new ArrayList<>();

        /*
         * 随机生成包含3个人类的List集合
         */
        List<Person> personList = GainList.getPersonList(3);
        System.out.println("排序前:" + personList);

        // 用于获取年龄数组
        int[] ageArr = new int[personList.size()];
        // 遍历集合,获取包含年龄的数组
        for (int i = 0; i < personList.size(); i++) {
            ageArr[i] = personList.get(i).getAge();
        }

        // 将包含年龄的数组排序 - 升序
        Arrays.sort(ageArr);

        for (int i = 0; i < ageArr.length; i++) {

            for (int j = 0; j < personList.size(); j++) {

                if (ageArr[i] == personList.get(j).getAge()) {

                    // 添加
                    sortList.add(personList.get(j));
                    // 移除,减少下次遍历次数
                    personList.remove(j);
                    // 防止报错
                    j--; 
                }
            }
        }
        System.out.println("排序后:" + sortList);
    }
}

运行得:
在这里插入图片描述

Map集合排序

Map集合排序的方式一其实跟实体类集合是一样的,这里我们来个降序排序:

package listsort;

import java.util.*;

/**
 * @ClassName ListMapSort
 * @Description List<map> 排序 - 老方法
 * @Author 古阙月
 * @Date 2020/12/25 16:40
 * @Version 1.0
 */
public class ListMapSort {
    public static void main(String[] args) {

        // 用于得到排序后返回的list
        List<Map> sortList = new ArrayList<>();

        /*
         * 随机生成包含3个map的List集合
         */
        List<Map> mapList = GainList.getMapList(3);
        System.out.println("排序前:" + mapList);

        // 用于获取年龄数组
        Integer[] ageArr = new Integer[mapList.size()];
        // 遍历集合,获取 包含年龄的数组
        for (int i = 0; i < mapList.size(); i++) {
            ageArr[i] = (int) mapList.get(i).get("age");
        }

        // 将包含年龄的数组排序 - 降序
        Arrays.sort(ageArr, Collections.reverseOrder());

        for (int i = 0; i < ageArr.length; i++) {

            for (int j = 0; j < mapList.size(); j++) {

                if (ageArr[i] == (int)mapList.get(j).get("age")) {

                    // 添加
                    sortList.add(mapList.get(j));
                    // 移除,减少下次遍历次数
                    mapList.remove(j);
                    // 防止报错
                    j--; 
                }
            }
        }
        System.out.println("排序后:" + sortList);
    }
}

运行得:
在这里插入图片描述

方式二

之前方式一的方式虽然可以实现效果,但是我们可以很容易发现两大缺点:

  1. 代码量太多导致可读性较差,不易于维护。
  2. 空间复杂度较高,new了一个新的集合。

那么有没有什么方法可以改进呢? 当然有了,不然我写这篇博客干嘛?

Java的api其实已经给我们提供方法了,如以实体类集合排序为例:

package listsort;

import java.util.*;

/**
 * @ClassName ListEntitySort2
 * @Description List<entity> 排序
 * @Author 古阙月
 * @Date 2020/12/25
 * @Version 1.0
 */
public class ListEntitySort2 {
    public static void main(String[] args) {

        /*
         * 随机生成包含3个人类的List集合
         */
        List<Person> personList = GainList.getPersonList(3);
        System.out.println("排序前:" + personList);

        /**
         * 将包含3个person实体的List集合按照年龄由低到高排序
         */
        Collections.sort(personList, new Comparator<Person>() {
            @Override
            public int compare(Person p1, Person p2) {
                
                int age1 = p1.getAge();
                int age2 = p2.getAge();

                if (age1 > age2) return 1;
                if (age1 < age2) return -1;

                return 0;
            }
        });

        System.out.println("排序后:" + personList);
    }
}

是不是感觉代码瞬间简洁了许多?运行得:
在这里插入图片描述
排序完成,very good!

比较

通过以上对比,我们可以很明显的发现方式二的两大优点:

  1. 代码可读性较好,易于维护。
  2. 空间复杂度较低。

那么,既然是程序,必定逃不过一个问题,那就是速率问题,或者说是时间复杂度

让我们来测试一下吧!!!

我们以Map集合排序为例,如用方式一对1000个Map进行排序:

package listsort;

import java.util.*;

/**
 * @ClassName ListMapSort
 * @Description List<map> 排序 - 老方法
 * @Author 古阙月
 * @Date 2020/12/25 16:40
 * @Version 1.0
 */
public class ListMapSort {
    public static void main(String[] args) {

        // 获取当前系统的毫秒数
        long begin = System.currentTimeMillis();

        // 用于得到排序后返回的list
        List<Map> sortList = new ArrayList<>();

        /*
         * 随机生成包含num个map的List集合
         */
        int num = 1000;
        List<Map> mapList = GainList.getMapList(num);
        System.out.println("排序前:" + mapList);

        // 用于获取年龄数组
        int[] ageArr = new int[mapList.size()];
        // 遍历集合,获取 包含年龄的数组
        for (int i = 0; i < mapList.size(); i++) {
            ageArr[i] = (int) mapList.get(i).get("age");
        }

        // 将包含年龄的数组排序 - 升序
        Arrays.sort(ageArr);
     
        for (int i = 0; i < ageArr.length; i++) {

            for (int j = 0; j < mapList.size(); j++) {

                if (ageArr[i] == (int)mapList.get(j).get("age")) {

                    // 添加
                    sortList.add(mapList.get(j));
                    // 移除,减少下次遍历次数
                    mapList.remove(j);
                    j--; // 防止报错
                }
            }
        }
        System.out.println("排序后:" + sortList);

        // 获取当前系统的毫秒数
        long end = System.currentTimeMillis();
        System.out.println("方法一排序含" + num + "个map的List集合,耗时:" + (double)(end - begin) / 1000 + "s");
    }
}

运行得:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PFWg7uyZ-1609996372556)(C:\Users\古阙月\AppData\Roaming\Typora\typora-user-images\image-20210107081455091.png)]
我们可以发现一号选手用时0.048秒,下面有请二号选手:

package listsort;

import java.util.*;

/**
 * @ClassName ListMapSort2
 * @Description List<map> 排序
 * @Author 古阙月
 * @Date 2020/12/25
 * @Version 1.0
 */
public class ListMapSort2 {
    public static void main(String[] args) {

        long begin = System.currentTimeMillis();

        /*
         * 随机生成包含num个map的List集合
         */
        int num = 1000;
        List<Map> mapList = GainList.getMapList(num);
        System.out.println("排序前:" + mapList);

        /**
         * 将包含3个map的List集合按照年龄由低到高排序
         */
        Collections.sort(mapList, new Comparator<Map>() {
            @Override
            public int compare(Map o1, Map o2) {
                
                int age1 = (int) o1.get("age");
                int age2 = (int) o2.get("age");

                if (age1 > age2) return 1;
                if (age1 < age2) return -1;

                return 0;
            }
        });

        System.out.println("排序后:" + mapList);

        long end = System.currentTimeMillis();
        System.out.println("方法一排序含" + num + "个map的List集合,耗时:" + (double)(end - begin) / 1000 + "s");

    }
}

运行得:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-19zxcy42-1609996372558)(C:\Users\古阙月\AppData\Roaming\Typora\typora-user-images\image-20210107081650045.png)]
这个时候,我们惊喜的发现,二号选手用时更短,仅为0.015秒,不信你多测几次便知。

哪怕,我们对方式一进行优化,如将 包含年龄的数组排序 的排序方法这一行代码

// 将包含年龄的数组排序 - 升序
Arrays.sort(ageArr);

改为快速排序

// 快速排序
QuickSort.quickSort(ageArr, 0, ageArr.length - 1);

虽然速率有所波动,但有时耗时会很少,有时会更多,效果仍是差强人意。所以这里我们可以发现方式二的第三大优点:

  1. 时间复杂度低,也就是速率比较快。

至于快速排序速率为什么会波动以及快速排序的代码,大家可以参考我的下面这篇博客中的第四章节<快速排序>,然后自行探究验证:
肝了几万字,送给看了《算法图解》却是主攻Java的你和我(上篇)

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值