前言

框架思维非常重要,和语言无关,这是一种非常重要的抽象能力,吹得厉害一点,就是要有高屋建瓴,统筹全局的能力。

树型结构的创建也是有套路的,下面由伟大的诗人chenqionghe给出套路框架,再分别套上相应的编程语言实现。

最终达到看到框架就能实现对应编程语言的代码,或者也可以直接copy实现拿去用~

迭代实现参考了这篇文章的思路列表list转树形结构:(python/golang/js/php),童鞋们可以看看这篇文章

需求

给定一级列表,构造出指定父ID的无限级树型结果

数据

[
{'id': 1, 'parent_id': 0, 'name': "A"},
{'id': 2, 'parent_id': 1, 'name': "AA"},
{'id': 3, 'parent_id': 1, 'name': "AB"},
{'id': 4, 'parent_id': 3, 'name': "ABA"},
{'id': 5, 'parent_id': 3, 'name': "ABB"},
{'id': 6, 'parent_id': 3, 'name': "ABC"},
{'id': 7, 'parent_id': 1, 'name': "AC"},
{'id': 8, 'parent_id': 7, 'name': "ACA"},
{'id': 9, 'parent_id': 8, 'name': "ACAA"},
{'id': 10, 'parent_id': 8, 'name': "ACAB"},
]

结果

最后构造成一颗根据父ID连接起来的树结构

{
"id": 1,
"parent_id": 0,
"name": "A",
"children": [
{
"id": 2,
"parent_id": 1,
"name": "AA",
"children": []
},
{
"id": 3,
"parent_id": 1,
"name": "AB",
"children": [
{
"id": 4,
"parent_id": 3,
"name": "ABA",
"children": []
},
{
"id": 5,
"parent_id": 3,
"name": "ABB",
"children": []
},
{
"id": 6,
"parent_id": 3,
"name": "ABC",
"children": []
}
]
},
{
"id": 7,
"parent_id": 1,
"name": "AC",
"children": [
{
"id": 8,
"parent_id": 7,
"name": "ACA",
"children": [
{
"id": 9,
"parent_id": 8,
"name": "ACAA",
"children": []
},
{
"id": 10,
"parent_id": 8,
"name": "ACAB",
"children": []
}
]
}
]
}
]
}

框架

递归框架

递归是一门艺术,用接近人类的语言来表达了程序,优点是代码较少,缺点是性能较差。

获取树(列表,父ID)
res = []
for 节点 in 列表:
if 节点的parent_id 等于 父ID
节点.children = 获取树(列表, 节点ID)
res.add(节点)
return res

迭代框架

迭代本身是创建一条引用链,将所有的节点串起来

获取树(列表,父ID)
memo = {}
for 节点 in 列表:
//构造memo给节点的父ID查找追加节点用
if 节点ID in memo:
节点.children = memo[节点ID].children //之前构造的children数组覆盖当前节点的children
memo[节点ID] = 节点
else
节点.children = []
memo[节点ID] = 节点 //给像父对象的children追加
if 节点父ID in memo:
memo[节点父ID].children.add(memo[节点ID]) //追加当前构造的ID节点
else:
memo[节点父ID] = {'children':[memo[节点ID]]} //初始化父对象再追加 return memo[父ID].children

递归框架实现

python

def get_tree_iterative(list_data, parent_id=0):
memo = {}
for v in list_data:
item_id = v['id']
item_paren_id = v['parent_id']
if item_id in memo:
v['children'] = memo[item_id]['children']
memo[item_id] = v
else:
v['children'] = []
memo[item_id] = v if item_paren_id in memo:
memo[item_paren_id]['children'].append(memo[item_id])
else:
memo[item_paren_id] = {'children': memo[item_id]}
return memo[parent_id]['children'] list_data = [
{'id': 1, 'parent_id': 0, 'name': "A"},
{'id': 2, 'parent_id': 1, 'name': "AA"},
{'id': 3, 'parent_id': 1, 'name': "AB"},
{'id': 4, 'parent_id': 3, 'name': "ABA"},
{'id': 5, 'parent_id': 3, 'name': "ABB"},
{'id': 6, 'parent_id': 3, 'name': "ABC"},
{'id': 7, 'parent_id': 1, 'name': "AC"},
{'id': 8, 'parent_id': 7, 'name': "ACA"},
{'id': 9, 'parent_id': 8, 'name': "ACAA"},
{'id': 10, 'parent_id': 8, 'name': "ACAB"},
] res = get_tree_iterative(list_data) import json print(json.dumps(res, indent=4))

运行如下

golang

package main

import (
"encoding/json"
"fmt"
) type Node struct {
Id int `json:"id"`
ParentId int `json:"parent_id"`
Name string `json:"name"`
Children []*Node `json:"children"`
} func getTreeRecursive(list []*Node, parentId int) []*Node {
res := make([]*Node, 0)
for _, v := range list {
if v.ParentId == parentId {
v.Children = getTreeRecursive(list, v.Id)
res = append(res, v)
}
}
return res
} func main() {
list := []*Node{
{4, 3, "ABA", nil},
{3, 1, "AB", nil},
{1, 0, "A", nil},
{2, 1, "AA", nil},
{5, 3, "ABB", nil},
{6, 3, "ABC", nil},
{7, 1, "AC", nil},
{8, 7, "ACA", nil},
{9, 8, "ACAA", nil},
{10, 8, "ACAB", nil},
}
res := getTreeRecursive(list, 0)
bytes, _ := json.MarshalIndent(res, "", " ")
fmt.Printf("%s\n", bytes)
}

运行如下

php

function getTreeRecursive(&$list, $parentId = 0)
{
$res = [];
foreach ($list as $k => $v) {
if ($v['parent_id'] == $parentId) {
$v['children'] = getTreeRecursive($list, $v['id']);
$res[] = $v;
}
}
return $res;
}
$list = [
['id' => 4, 'parent_id' => 3, 'name' => "ABA"],
['id' => 3, 'parent_id' => 1, 'name' => "AB"],
['id' => 1, 'parent_id' => 0, 'name' => "A"],
['id' => 2, 'parent_id' => 1, 'name' => "AA"],
['id' => 5, 'parent_id' => 3, 'name' => "ABB"],
['id' => 6, 'parent_id' => 3, 'name' => "ABC"],
['id' => 7, 'parent_id' => 1, 'name' => "AC"],
['id' => 8, 'parent_id' => 7, 'name' => "ACA"],
['id' => 9, 'parent_id' => 8, 'name' => "ACAA"],
['id' => 10, 'parent_id' => 8, 'name' => "ACAB"],
];
$res = getTreeRecursive($list);
echo json_encode($res,JSON_PRETTY_PRINT);

运行结果如下

js

function getTreeRecursive(listData, parentId = 0) {
let res = []
listData.forEach((v, k) => {
if (v.parent_id == parentId) {
v.children = getTreeRecursive(listData, v.id)
res.push(v)
}
})
return res
} dataList = [
{'id': 1, 'parent_id': 0, 'name': "A"},
{'id': 2, 'parent_id': 1, 'name': "AA"},
{'id': 3, 'parent_id': 1, 'name': "AB"},
{'id': 4, 'parent_id': 3, 'name': "ABA"},
{'id': 5, 'parent_id': 3, 'name': "ABB"},
{'id': 6, 'parent_id': 3, 'name': "ABC"},
{'id': 7, 'parent_id': 1, 'name': "AC"},
{'id': 8, 'parent_id': 7, 'name': "ACA"},
{'id': 9, 'parent_id': 8, 'name': "ACAA"},
{'id': 10, 'parent_id': 8, 'name': "ACAB"},
] let res = getTreeRecursive(dataList);
console.log((JSON.stringify(res, null, 4)))

运行如下

迭代框架实现

python

def get_tree_iterative(list_data, parent_id=0):
memo = {}
for v in list_data:
id_ = v['id']
item_paren_id = v['parent_id']
if id_ in memo:
v['children'] = memo[id_]['children']
memo[id_] = v
else:
v['children'] = []
memo[id_] = v if item_paren_id in memo:
memo[item_paren_id]['children'].append(memo[id_])
else:
memo[item_paren_id] = {'children': memo[id_]}
return memo[parent_id]['children'] list_data = [
{'id': 1, 'parent_id': 0, 'name': "A"},
{'id': 2, 'parent_id': 1, 'name': "AA"},
{'id': 3, 'parent_id': 1, 'name': "AB"},
{'id': 4, 'parent_id': 3, 'name': "ABA"},
{'id': 5, 'parent_id': 3, 'name': "ABB"},
{'id': 6, 'parent_id': 3, 'name': "ABC"},
{'id': 7, 'parent_id': 1, 'name': "AC"},
{'id': 8, 'parent_id': 7, 'name': "ACA"},
{'id': 9, 'parent_id': 8, 'name': "ACAA"},
{'id': 10, 'parent_id': 8, 'name': "ACAB"},
] res = get_tree_iterative(list_data) import json print(json.dumps(res, indent=4))

运行如下

golang

package main

import (
"encoding/json"
"fmt"
) type Node struct {
Id int `json:"id"`
ParentId int `json:"parent_id"`
Name string `json:"name"`
Children []*Node `json:"children"`
} func getTreeIterative(list []*Node, parentId int) []*Node {
memo := make(map[int]*Node)
for _, v := range list {
if _, ok := memo[v.Id]; ok {
v.Children = memo[v.Id].Children
memo[v.Id] = v
} else {
v.Children = make([]*Node, 0)
memo[v.Id] = v
}
if _, ok := memo[v.ParentId]; ok {
memo[v.ParentId].Children = append(memo[v.ParentId].Children, memo[v.Id])
} else {
memo[v.ParentId] = &Node{Children: []*Node{memo[v.Id]}}
}
}
return memo[parentId].Children } func main() {
list := []*Node{
{4, 3, "ABA", nil},
{3, 1, "AB", nil},
{1, 0, "A", nil},
{2, 1, "AA", nil},
{5, 3, "ABB", nil},
{6, 3, "ABC", nil},
{7, 1, "AC", nil},
{8, 7, "ACA", nil},
{9, 8, "ACAA", nil},
{10, 8, "ACAB", nil},
}
res := getTreeIterative(list, 0)
bytes, _ := json.MarshalIndent(res, "", " ")
fmt.Printf("%s\n", bytes)
}

运行如下

php

function getTreeIterative($list, $parentId = 0)
{
$memo = [];
foreach ($list as &$v) {
$id = $v['id'];
$itemParentId = $v['parent_id'];
if (isset($memo[$id])) {
$v['children'] = &$memo[$id]['children'];
$memo[$id] = $v;
} else {
$v['children'] = [];
$memo[$id] = $v;
}
if (isset($memo[$itemParentId])) {
$memo[$itemParentId]['children'][] = &$memo[$id];
} else {
$memo[$itemParentId] = ['children' => [&$memo[$id]]];
}
}
return $memo[$parentId]['children'];
} $list = [
['id' => 4, 'parent_id' => 3, 'name' => "ABA"],
['id' => 3, 'parent_id' => 1, 'name' => "AB"],
['id' => 1, 'parent_id' => 0, 'name' => "A"],
['id' => 2, 'parent_id' => 1, 'name' => "AA"],
['id' => 5, 'parent_id' => 3, 'name' => "ABB"],
['id' => 6, 'parent_id' => 3, 'name' => "ABC"],
['id' => 7, 'parent_id' => 1, 'name' => "AC"],
['id' => 8, 'parent_id' => 7, 'name' => "ACA"],
['id' => 9, 'parent_id' => 8, 'name' => "ACAA"],
['id' => 10, 'parent_id' => 8, 'name' => "ACAB"],
];
$res = getTreeIterative($list);
echo json_encode($res, JSON_PRETTY_PRINT);

运行结果如下

js

function getTreeIterative(listData, parentId = 0) {
let memo = {};
listData.forEach((v, k) => {
let id = v.id
let itemParentId = v.parent_id if (memo[id]) {
v.children = memo[id].children
memo[id] = v
} else {
v.children = []
memo[id] = v;
} if (memo[itemParentId]) {
memo[itemParentId].children.push(memo[id]);
} else {
memo[itemParentId] = {children: [memo[id]]};
}
}) return memo[parentId].children
} dataList = [
{'id': 1, 'parent_id': 0, 'name': "A"},
{'id': 2, 'parent_id': 1, 'name': "AA"},
{'id': 3, 'parent_id': 1, 'name': "AB"},
{'id': 4, 'parent_id': 3, 'name': "ABA"},
{'id': 5, 'parent_id': 3, 'name': "ABB"},
{'id': 6, 'parent_id': 3, 'name': "ABC"},
{'id': 7, 'parent_id': 1, 'name': "AC"},
{'id': 8, 'parent_id': 7, 'name': "ACA"},
{'id': 9, 'parent_id': 8, 'name': "ACAA"},
{'id': 10, 'parent_id': 8, 'name': "ACAB"},
] let res = getTreeIterative(dataList);
console.log((JSON.stringify(res, null, 4)))

运行如下

以后如果想用直接来拷贝代码就行,就是这么简单~

构造无限级树的框架套路,附上python/golang/php/js实现的更多相关文章

  1. silverlight中递归构造无限级树treeview+checkbox

    两个实体,其实一个实体也能构造出来,我这里是为了增加一个 checkbox //第一个实体 public class person { public int no { get; set; } publ ...

  2. 轻量级表达式树解析框架Faller

    有话说 之前我写了3篇关于表达式树解析的文章 干货!表达式树解析"框架"(1) 干货!表达式树解析"框架"(2) 干货!表达式树解析"框架" ...

  3. 干货!表达式树解析"框架"(1)

    最新设计请移步 轻量级表达式树解析框架Faller http://www.cnblogs.com/blqw/p/Faller.html 关于我和表达式树 其实我也没有深入了解表达式树一些内在实现的原理 ...

  4. 干货!表达式树解析"框架"(2)

    最新设计请移步 轻量级表达式树解析框架Faller http://www.cnblogs.com/blqw/p/Faller.html 为了过个好年,我还是赶快把这篇完成了吧 声明 本文内容需要有一定 ...

  5. 表达式树解析"框架"

    干货!表达式树解析"框架"(2)   为了过个好年,我还是赶快把这篇完成了吧 声明 本文内容需要有一定基础的开发人员才可轻松阅读,如果有难以理解的地方可以跟帖询问,但我也不一定能回 ...

  6. Django,Flask,Tornado三大框架对比,Python几种主流框架,13个Python web框架比较,2018年Python web五大主流框架

    Django 与 Tornado 各自的优缺点Django优点: 大和全(重量级框架)自带orm,template,view 需要的功能也可以去找第三方的app注重高效开发全自动化的管理后台(只需要使 ...

  7. 通过有序线性结构构造AVL树

    通过有序线性结构构造AVL树 本博客旨在结局利用有序数组和有序链表构造平衡二叉树(下文使用AVL树代指)问题. 直接通过旋转来构造AVL树似乎是一个不错的选择,但是稍加分析就会发现,这样平白无故做了许 ...

  8. 某互联网后台自动化组合测试框架RF+Sikuli+Python脚本

    某互联网后台自动化组合测试框架RF+Sikuli+Python脚本 http://www.jianshu.com/p/b3e204c8651a 字数949 阅读323 评论1 喜欢0 一.**Robo ...

  9. 干货!表达式树解析"框架"(3)

    最新设计请移步 轻量级表达式树解析框架Faller http://www.cnblogs.com/blqw/p/Faller.html 这应该是年前最后一篇了,接下来的时间就要陪陪老婆孩子了 关于表达 ...

随机推荐

  1. 利用Xposed Hook打印Java函数调用堆栈信息的几种方法

    本文博客链接:http://blog.csdn.net/QQ1084283172/article/details/79378374 在进行Android逆向分析的时候,经常需要进行动态调试栈回溯,查看 ...

  2. android添加账户源码浅析

    上篇粗略的分析android添加账号的流程,本篇深入的解析下执行步骤.先来看图片,取自深入理解android卷2: 上图详细的分析了addAccount的流程,下面我们结合源码来理解它 1.addAc ...

  3. VS Code插件推荐-Settings Sync

    Settings Sync功能 将vscode的本地设置.插件保存至远端,方便保存 Usage 插件市场安装Setting Sync之后,⌘+P输入>sync,即可看到相关操作,选中点击之后官方 ...

  4. 修改wordpress版权信息

    修改页脚版权信息位置:找到C:\wamp64\www\wordpress\wp-content\themes\travelify\library\structure\footer-extensions ...

  5. Govern Service 基于 Redis 的服务治理平台

    Govern Service 基于 Redis 的服务治理平台(服务注册/发现 & 配置中心) Govern Service 是一个轻量级.低成本的服务注册.服务发现. 配置服务 SDK,通过 ...

  6. Java安全之Fastjson反序列化漏洞分析

    Java安全之Fastjson反序列化漏洞分析 首发:先知论坛 0x00 前言 在前面的RMI和JNDI注入学习里面为本次的Fastjson打了一个比较好的基础.利于后面的漏洞分析. 0x01 Fas ...

  7. 03.21 ICPC训练联盟周赛:UCF Local Programming Contest 2018正式赛

    B Breaking Branches 题意:两个人比赛折枝,谁剩下最后1,无法折出整数即为输 思路:树枝长n,若是奇数,则Bob胜出,若是偶数,则Alice胜出,且需要输出1: 1 #include ...

  8. 拦截器(Interceptor)与过滤器(Filter)

    目录 用户的普通Http请求执行顺序 过滤器.拦截器添加后的执行顺序 拦截器(Interceptor)的基本定义 拦截器(Interceptor)必须实现的三个方法 单个拦截器(Interceptor ...

  9. 拷贝构造函数第一个参数最好使用const

    拷贝构造函数的第一个参数要求是自身类型的引用,但是没有一定要求具有底层const属性即对常量的引用,但是使用时最好加上const,原因是我们可能在某些"不知道"的情况下对常量对象调 ...

  10. Java语言的三大特性

    Java语言的三大特性 1.封装 1.1  概念: 封装也成为信息异常,隐藏对象的属性和实现细节,仅对外公开接口(外部不可以直接看到对象的属性细节并且不能直接更改属性的值,只能通过方法来读取或更改属性 ...