树形结构快速生成

2023年 8月 23日 28.6k 0

背景

相信大家都遇到过树形结构,像是文件列表、多级菜单、评论区的设计等等,我们都发现它有很多层级,第一级可以有多个,下边的每一个层级也可以有多个;有的可以设计成无限层级的,有的只能设计成两级。那么作为程序员,我觉得应该具备这种思维:程序的拓展性。就像shigen接手需求一样,上次接到了评论回复的需求,产品觉得两级回复和多级回复可以分成两期做,细心的我就发现这完全可以整成一个需求做呢。于是我一次性把之后的都做了。

我们先分析一下具体的场景:

我们常常会遇到多级文件,类似我们电脑的文件管理系统。我们可以把每个文件夹和文件抽象一下,在linux系统中,文件就包括文本文件和文件夹。OK,万物皆文件shigen就在这里狂一下。那它们要根据什么关联起来呢,数据库怎么存储呢?

文件系统多级文件

分析

目前,我们主要的解决方案是这样的。

     item_list = [
         Item(111, "one", None, None),
         Item(111-1, "one", None, None),
         Item(222, "two", 111, None),
         Item(333, "three", 111, None),
         Item(444, "four", 333, None),
         Item(444-1, "four", 333, None),
         Item(444-2, "four", 444-1, None),
     ]

我们只需要存储单条数据就可以,那它们的关联就需要构造函数的第三个参数pid,保存自己上一个节点的id,如果上一个节点的id(pid)是空的,OK,那它就是第一级别的。注意,第一级别的可能有多个。Item的构造方法是这样的:

 class Item():
 ​
     def __init__(self, id: int, name: str, pid: Optional[int], children: Optional[List]):
         self.id = id
         self.name = name
         self.pid = pid
         self.__children = children

那么,分析起来发现就是几句话,代码怎么实现呢?shigen在这里列举了两种语言的实现方式:javapython。来一起看看吧!

代码实现

Java

在来到Java这一步,我不会使用传统的递归的方式,我使用的是java8,所以我更喜欢用stream+lambda表达式,写起来异常的简洁,别人不夸优雅都不行!

Item类的定义和python代码案例的是一样的,java的定义是这样的:

     @Data
     @AllArgsConstructor
     static class Item {
 ​
         private Integer id;
         private String name;
         private Integer pid;
         private List children;
 ​
     }

那怎么实现这个tree结构呢?shigen用的一个函数,仅仅三行代码,是三行!

     private static List getTree(ArrayList items) {
         // 获得非顶级节点的数据并按照pid分组
         Map nodeMap = items.stream().filter(item -> item.getPid() != null).collect(Collectors.groupingBy(Item::getPid));
 ​
         // 循环设置子节点
         items.forEach(item -> item.setChildren(nodeMap.get(item.id)));
 ​
         // 获得根节点的数据
         List treeNode = items.stream().filter(node -> node.getPid() == null).collect(Collectors.toList());
         return treeNode;
     }

这是一个通用的方法,我把我的代码截图也贴上来。

Java tree的代码实现

这边shigen也在思考把这个方法做成通用的,这样就可以作为一个工具类使用了。也欢迎伙伴们来交流一下。

python

shigen对这个案例提供了双语言的支持。但是不得不说在和javastream对比之下,python的代码还是显得比较繁琐了。但是也是一种解决思路和参考。

 def build_tree_structure(items:List[Item]) -> List[Item]:
     
     # 获得顶级节点
     treeNode = list(filter(lambda item: item.pid is None, items))
     
     for node in treeNode:
         node.children = get_children(node, items)
 ​
     return treeNode
 ​
 ​
 def get_children(root:Item, items:List[Item]) -> Item:
     children = []
     for item in items:
         if item.pid  == root.id:
             item.children = get_children(item, items)
             children.append(item)
     return children

其实这里用到了递归的方式,先获得所有的第一级节点,然后根据第一层节点的id去匹配子级的id。这样重复的步骤,就可以使用递归来实现了,递归的终止条件就是item.pid != root.id。这个代码shigen目前已经写到最简洁了,还有其它的优化思路的,也欢迎评论区交流一下。

最后贴上我的python代码实现截图:

python代码实现

好了,以上就是shigen和大家分享的树形结构的快速生成的全部内容了。

shigen一起,每天不一样!

相关文章

服务器端口转发,带你了解服务器端口转发
服务器开放端口,服务器开放端口的步骤
产品推荐:7月受欢迎AI容器镜像来了,有Qwen系列大模型镜像
如何使用 WinGet 下载 Microsoft Store 应用
百度搜索:蓝易云 – 熟悉ubuntu apt-get命令详解
百度搜索:蓝易云 – 域名解析成功但ping不通解决方案

发布评论