zoukankan      html  css  js  c++  java
  • 查询list转化为tree的两种方式及排序

    方式一,数据库查询tree;

    MyBatis collection 集合

    MyBatis 是数据持久层框架,支持定制化 SQL、存储过程以及高级映射。尤其强大在于它的映射语句,比如高级映射中的 collection 集合。

    collection 集合,集合常用的两个场景是集合的嵌套查询、集合的嵌套结果。集合的嵌套结果就是查询结果对应嵌套子对象。这里就是利用 collection 集合嵌套查询树形节点。下面来一一实现。

    查询树形节点 Web 案例

    创建数据库表

    节点表:

    CREATE TABLE `node` (
      `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
      `name` varchar(32) NOT NULL,
      `parent_id` int(11) unsigned NOT NULL,
      PRIMARY KEY (`id`),
      KEY `parent_id` (`parent_id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4 COMMENT='节点表'
    

    简单的节点父子关系设计,下面插入几条数据:

    INSERT INTO node (name, parent_id) VALUES ('一级节点A', 0);
    INSERT INTO node (name, parent_id) VALUES ('一级节点B', 0);
    INSERT INTO node (name, parent_id) VALUES ('一级节点C', 0);
    INSERT INTO node (name, parent_id) VALUES ('二级节点AA', 1);
    INSERT INTO node (name, parent_id) VALUES ('二级节点aa', 1);
    INSERT INTO node (name, parent_id) VALUES ('二级节点BB', 2);
    INSERT INTO node (name, parent_id) VALUES ('三级级节点AAA', 4);
    INSERT INTO node (name, parent_id) VALUES ('三级级节点aaa', 4);
    INSERT INTO node (name, parent_id) VALUES ('三级级节点BBB', 6);

    重要的还是看 collection 在 xml 的映射实现,NodeMapper.xml 代码如下:

    <mapper namespace="org.mybatis.dao.NodeDao">
    
      <resultMap id="BaseTreeResultMap" type="org.mybatis.domain.Node">
        <result column="id" property="id"/>
        <result column="name" property="name"/>
        <collection column="id" property="next" javaType="java.util.ArrayList"
                    ofType="org.mybatis.domain.Node" select="getNextNodeTree"/>
      </resultMap>
    
      <resultMap id="NextTreeResultMap" type="org.mybatis.domain.Node">
        <result column="id" property="id"/>
        <result column="name" property="name"/>
        <collection column="id" property="next" javaType="java.util.ArrayList"
                    ofType="org.mybatis.domain.Node" select="getNextNodeTree"/>
      </resultMap>
    
      <sql id="Base_Column_List">
            id, name
        </sql>
    
      <select id="getNextNodeTree" resultMap="NextTreeResultMap">
        SELECT
        <include refid="Base_Column_List"/>
        FROM node
        WHERE parent_id = #{id}
      </select>
    
      <select id="getNodeTree" resultMap="BaseTreeResultMap">
        SELECT
        <include refid="Base_Column_List"/>
        FROM node
        WHERE parent_id = 0
      </select>
    
    </mapper>
    

    在 dao 层,我们只调用 getNodeTree 方法,parent_id = 0 代表顶级节点。然后通过 collection 节点继续调用 getNextNodeTree 方法进行循环调用。

    <collection column="id" property="next" javaType="java.util.ArrayList"
                    ofType="org.mybatis.domain.Node" select="getNextNodeTree"/>
    

    以下是关键的知识点:

    • column 代表会拿父节点 id ,作为参数获取 next 对象
    • javaType 代表 next 对象是个列表,其实可以省略不写
    • ofType 用来区分 JavaBean 属性类型和集合包含的类型
    • select 是用来执行循环哪个 SQL

    工程代码地址:https://github.com/JeffLi1993/myabtis-learning-example
    工程演示后的结果如图所示:

     
     
     
    方式二,内存计算
       方式一查询数据库效率较低,方式二一次查询所有数据,任何用stream流来计算转化为树,建议采用

    普通list转树状list

    public static List<User> list2tree(List<User> list) {
    List<User> result = new ArrayList<>();
    Map<Object, User> hash = list.stream().collect(Collectors.toMap(u -> u.getId(), u -> u));
    for (User u : list) {
    User p = hash.get(u.getParent());
    if (p == null) {
    result.add(u);
    } else {
    if (p.getChildren() == null) {
    p.setChildren(new ArrayList<>());
    }
    p.getChildren().add(u);
    }
    }
    return result;
    }

    树状list转普通list

    public static List<User> tree2list(List<User> list) {
    List<User> result = new ArrayList<>();
    for (User u : list) {
    List<User> c = u.getChildren();
    result.add(u);
    if (!CollectionUtils.isEmpty(c)) {
    result.addAll(tree2list(c));
    u.setChildren(null);//
    }
    }
    return result;
    }

    java8 stream多字段排序

    使用java8新特性,下面先来点基础的

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    List<类> list; 代表某集合
     
    //返回 对象集合以类属性一升序排序
     
    list.stream().sorted(Comparator.comparing(类::属性一));
     
    //返回 对象集合以类属性一降序排序 注意两种写法
     
    list.stream().sorted(Comparator.comparing(类::属性一).reversed());//先以属性一升序,结果进行属性一降序
     
    list.stream().sorted(Comparator.comparing(类::属性一,Comparator.reverseOrder()));//以属性一降序
     
    //返回 对象集合以类属性一升序 属性二升序
     
    list.stream().sorted(Comparator.comparing(类::属性一).thenComparing(类::属性二));
     
    //返回 对象集合以类属性一降序 属性二升序 注意两种写法
     
    list.stream().sorted(Comparator.comparing(类::属性一).reversed().thenComparing(类::属性二));//先以属性一升序,升序结果进行属性一降序,再进行属性二升序
     
    list.stream().sorted(Comparator.comparing(类::属性一,Comparator.reverseOrder()).thenComparing(类::属性二));//先以属性一降序,再进行属性二升序
     
    //返回 对象集合以类属性一降序 属性二降序 注意两种写法
     
    list.stream().sorted(Comparator.comparing(类::属性一).reversed().thenComparing(类::属性二,Comparator.reverseOrder()));//先以属性一升序,升序结果进行属性一降序,再进行属性二降序
     
    list.stream().sorted(Comparator.comparing(类::属性一,Comparator.reverseOrder()).thenComparing(类::属性二,Comparator.reverseOrder()));//先以属性一降序,再进行属性二降序
     
    //返回 对象集合以类属性一升序 属性二降序 注意两种写法
     
    list.stream().sorted(Comparator.comparing(类::属性一).reversed().thenComparing(类::属性二).reversed());//先以属性一升序,升序结果进行属性一降序,再进行属性二升序,结果进行属性一降序属性二降序
     
    list.stream().sorted(Comparator.comparing(类::属性一).thenComparing(类::属性二,Comparator.reverseOrder()));//先以属性一升序,再进行属性二降序<br><br><br>

    通过以上例子我们可以发现

    1. Comparator.comparing(类::属性一).reversed();

    2. Comparator.comparing(类::属性一,Comparator.reverseOrder());

    两种排序是完全不一样的,一定要区分开来 1 是得到排序结果后再排序,2是直接进行排序,很多人会混淆导致理解出错,2更好理解,建议使用2

    3.注意排序后需要另外一个lis来接收List<xxx> list= Stream.sort(xxx).collect(toList());

    class testRun {
        public static void main(String[] args) {
            List<test> testList = new ArrayList<>();
            Date d = DateUtils.now();
            for (int i = 1; i <= 3; i++) {
                test t = new test(i, DateUtils.addDays(d, i));
                testList.add(t);
            }
            for (int i = 1; i <= 3; i++) {
                test t = new test(i, DateUtils.addMonths(d, i));
                testList.add(t);
            }
     
            testList.forEach(o -> {
                System.out.println(o.toString());
            });
            List<test> sort = testList.stream().sorted(Comparator.comparing(test::getState).thenComparing(test::getTime,Comparator.reverseOrder())).collect(toList());
            System.out.println("------------------------------------");
            sort.forEach(o -> {
                System.out.println(o.toString());
            });
     
     
        }
    }


    参考

    链接:https://www.jianshu.com/p/fa20d4bd8ad4

    链接:https://blog.csdn.net/qq_41991665/article/details/90484690

     
  • 相关阅读:
    Java 泛型 泛型的约束与局限性
    Java 泛型 泛型方法
    Java 泛型 泛型数组
    Java 泛型 协变性、逆变性
    Java 泛型 协变式覆盖和泛型重载
    Java 泛型 泛型代码和虚拟机
    Insertion Sort List
    Remove Duplicates from Sorted List II
    String to Integer (atoi)
    SpringMvc源码入门
  • 原文地址:https://www.cnblogs.com/yuluoxingkong/p/11912821.html
Copyright © 2011-2022 走看看