当前位置:网站首页>php 实现无限极分类树(递归及其优化)
php 实现无限极分类树(递归及其优化)
2022-06-12 17:09:00 【风碎峰】
一、需求描述
接口功能描述:
查询国内完整的行政区划信息,即所有的省份、省份下所有的地级市、地级市下所有的区县,所有的数据只返回 id、admincode、name、simple_name、lng、lat 六个字段。
二、背景概述
目标表结构:
CREATE TABLE `lbs_district` (
`id` char(19) NOT NULL DEFAULT '0' COMMENT '19位ID',
`parent_id` char(19) NOT NULL DEFAULT '0' COMMENT '上级行政区划的19位ID',
`name` varchar(100) NOT NULL DEFAULT '' COMMENT '名称',
`level` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '类型:1:国家与地区,2:省份,3:地级市,4:区县,5:街道,6:乡镇、其他,7:面商圈,8:点商圈',
`level_name` varchar(20) NOT NULL DEFAULT '' COMMENT '类型名称:1:country,2:province,3:city,4:county,5:town,6:town,7:business,8:business',
`lng` float(10,6) NOT NULL DEFAULT '0.000000' COMMENT '中心点 longitude,即经度坐标',
`lat` float(10,6) NOT NULL DEFAULT '0.000000' COMMENT '中心点 latitude,即纬度坐标',
`admincode` char(6) NOT NULL DEFAULT '0' COMMENT '标准国家行政区划6位编码',
`is_foreign` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '类型:1:大陆及港澳,2:台湾及国外',
`deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '标识删除状态:0:不删除,1:删除',
`deltime` datetime NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '删除时间',
`ctime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`mtime` datetime NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '更新时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='行政区划和商圈信息表';
从库中获取行政区划数据后,以树形结构输出省、市、区县三级行政区划数据。
三、代码实现
考虑到从库中获取的数据为3000多条,基本囊括了全国的数据,所以考虑用递归实现也是可以的。
<?php
/**
* <p>
* 接口功能描述:查询国内完整的行政区划信息
* </p>
*
* <p>
* 接口输出的数据结构说明:输出数据以JSON数组形式返回,例:
* <blockquote><pre>
* [{
* "id":"8008611000000000000",
* "parent_id":"8008600000000000000",
* "admincode":"110000",
* "name":"北京市",
* "simple_name":"北京",
* "lng":"116.405289",
* "lat":"39.904987"
* },
* {
* "id":"8008612010500000000",
* "parent_id":"8008600000000000000",
* "admincode":"120105",
* "name":"河北省",
* "simple_name":"河北",
* "lng":"117.201569",
* "lat":"39.156631"
* }]
* <blockquote><pre>
* </p>
*
* @author bingqing5
* @date 2022/05/16
*/
header('Content-type: application/json');
require_once 'district_common.php';
/**
* 生成树形结构数据
* @param $items 以数组形式存储的处理目标数据
* @param $parentId 父节点的ID
* @return array
*/
function generateTree($items , $parentId)
{
// 初始化一个数组,用以存储输出数据
$tree = array();
/* 遍历数组,对数据递归处理*/
foreach($items as $k => $v)
{
/* 判断当前节点的parentId是否与参数相同?
* 如果相同,沿着同父节点向下递归。进一步
* 判断当前节点的子节点是否不为空,如果不
* 为空,将当前节点归入当前父节点的children中
*/
if($v['parent_id'] == $parentId)
{
$set = generateTree($items , $v['id']);
if (!empty($set))
{
$v['children'] = generateTree($items , $v['id']);
}
$tree[] = $v;
}
}
return $tree;
}
$sql = "
SELECT
ld.id,
ld.parent_id,
ld.admincode,
ld.name,
lde.simple_name,
ld.lng,
ld.lat,
ld.level
FROM
lbs_district ld
LEFT JOIN lbs_district_extends lde ON ld.id = lde.lbs_district_id
WHERE
ld.is_foreign = 1
AND ld.level IN (2,3,4)
ORDER BY ld.id ASC";
$return = $db->getAll($sql);
// 接口要求获取国内省、市、区县三级行政区划树形结构,所以根节点取中国行政区划ID
$treeRes = generateTree($return, '8008600000000000000');
echo json_encode($treeRes);;
$db->close();
?>以上代码因为公司内部项目环境原因,使用的是PHP5,递归部分的代码用PHP7可以这样写:
function generateTree($items , $parentId)
{
$tree = [];
foreach($items as $k => $v)
{
if($v['parent_id'] == $parentId)
{
if (!empty(generateTree($items , $v['id'])))
{
$v['childs'] = generateTree($items , $v['id']);
}
$tree[] = $v;
}
}
return $tree;
}话说,PHP真的是坑,笔者用PHP7的写法线上跑,总是报错。因为笔者本职是Java开发,对PHP那是一窍不通,也是在组长要求下临时承担了PHP开发任务,在写代码的时候难免总是带着Java的语法习惯。。。
四、优化
将代码提交后,线上测试,结果如图:

很显然,接口拿到数据需要20s,这是一个不可接受的事。之后,同事在此基础上完成了优化,代码如下:
<?php
/**
* <p>
* 接口功能描述:查询国内完整的行政区划信息
* </p>
*
* <p>
* 接口输出的数据结构说明:输出数据以JSON数组形式返回,例:
* <blockquote><pre>
* [{
* "id":"8008611000000000000",
* "parent_id":"8008600000000000000",
* "admincode":"110000",
* "name":"北京市",
* "simple_name":"北京",
* "lng":"116.405289",
* "lat":"39.904987"
* },
* {
* "id":"8008612010500000000",
* "parent_id":"8008600000000000000",
* "admincode":"120105",
* "name":"河北省",
* "simple_name":"河北",
* "lng":"117.201569",
* "lat":"39.156631"
* }]
* <blockquote><pre>
* </p>
*
* @author bingqing5
* @date 2022/05/16
*/
header('Content-type: application/json');
require_once 'district_common.php';
/**
* 生成树形结构数据
* @param $items 以数组形式存储的处理目标数据
* @param $parentId 父节点的ID
* @return array
*/
function generateTree($items , $parentId) {
// 初始化一个数组,用以存储输出数据
$tree = array();
/* 遍历数组,对数据递归处理*/
foreach($items as $k => $v) {
/* 判断当前节点的parentId是否与参数相同?
* 如果相同,沿着同父节点向下递归。进一步
* 判断当前节点的子节点是否不为空,如果不
* 为空,将当前节点归入当前父节点的children中
*/
if(isset($v['parent_id']) && $v['parent_id'] == $parentId) {
if($v['level']!=4){//只有省和地级市才有下级子节点
$set = generateTree($items , $v['id']);
if (!empty($set)) {
$v['children'] = generateTree($items , $v['id']);
}
// $v['children'] = generateTree($items , $v['id']);
}
unset($v['parent_id']);//较少输出字段,提高接口速度
$tree[] = $v;
}
}
return $tree;
}
//数据太多,只输出一些基础数据,取消关联,否会会很慢
/*
$sql = "
SELECT
ld.id,
ld.parent_id,
ld.admincode,
ld.name,
lde.simple_name,
ld.lng,
ld.lat,
ld.level
FROM
lbs_district ld
LEFT JOIN lbs_district_extends lde ON ld.id = lde.lbs_district_id
WHERE
ld.is_foreign = 1
AND ld.level IN (2,3,4)
ORDER BY ld.id ASC";
*/
$sql = "
SELECT
ld.id,
ld.parent_id,
ld.name,
ld.lng,
ld.lat,
ld.level
FROM
lbs_district ld
WHERE
ld.is_foreign = 1
AND ld.level IN (2,3,4)
ORDER BY ld.id ASC";
$return = $db->getAll($sql);
// 接口要求获取国内省、市、区县三级行政区划树形结构,所以根节点取中国行政区划ID
$treeRes = generateTree($return, '8008600000000000000');
echo json_encode($treeRes);;
$db->close();
?>优化后接口的响应速度大大提升,如图:

边栏推荐
- 1723. 完成所有工作的最短时间
- A variety of Qt development methods, which do you choose?
- R语言使用epiDisplay包的tabpct函数生成二维列联表并使用马赛克图可视化列联表(二维列联表、边际频数、以及按行、按列的比例)、自定义设置ylab参数设置Y轴的轴标签文本(y axis)
- (5) Outputs and outputs
- R language calculates data Table specifies the mean value of a numeric variable when the value of one grouped variable is fixed and another grouped variable
- Go的变量
- 2080 virtual machine login command
- "Upgrade strategy" of two new committers
- 启牛开的证券账户安全吗?合法吗?
- Gerrit触发Jenkins SonarQube扫描
猜你喜欢

有趣的 LD_PRELOAD

Uniapp壁纸小程序源码/双端微信抖音小程序源码

Exclusive interview with oppo find X5 Product Manager: deeply cultivate self-developed chips to create the ultimate flagship experience with the highest standards

Google browser debugging skills

男神女神投票源码 v5.5.21 投票源码

Dongfeng Yueda Kia, Tencent advertising and hero League mobile game professional league cooperate to build a new E-sports ecology

"Upgrade strategy" of two new committers

Male god goddess voting source code v5.5.21 voting source code

Kill program errors in the cradle with spotbugs

Gerrit+2 triggers Jenkins task
随机推荐
Unit sshd. service could not be found
(3) Golang - data type
Flink 维表异步查询的实现以及问题排查
Introduction to several common functions of fiddler packet capturing (stop packet capturing, clear session window contents, filter requests, decode, set breakpoints...)
Unit sshd.service could not be found
Sudo of uabntu
1723. 完成所有工作的最短时间
The R language uses the tablestack function of epidisplay package to generate statistical analysis tables based on grouped variables (including descriptive statistical analysis, hypothesis test, diffe
MySQL提权总结
PAT甲级 1142 最大团
Download PHP source code of leaf sharing station
如何查看、修改和删除SSH
R语言使用epiDisplay包的tableStack函数基于分组变量生成统计分析表(包含描述性统计分析、假设检验、不同数据使用不同的统计量和假设检验方法)、自定义配置是否显示统计检验内容
大端模式和小端模式的區別
Installation and use of rolabelimg
(8) Goto keyword
邱盛昌:OPPO商业化数据体系建设实战
新媒体运营素材网站分享,让你创作时事半功倍
Atlassian Confluence 远程代码执行漏洞(CVE-2022-26134)漏洞复现
每天5分钟玩转Kubernetes | 汇总