Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >巧用指针/引用实现多级省市区嵌套

巧用指针/引用实现多级省市区嵌套

原创
作者头像
yaxin
发布于 2021-01-22 10:35:22
发布于 2021-01-22 10:35:22
1.2K0
举报
文章被收录于专栏:DevOps BoyDevOps Boy

开发中经常遇到需要将一个二维结构的数据转换为N级嵌套(如多级菜单、省市区嵌套等),一般遇到这种问题我们会借助数据表添加冗余列配合代码,高级点的可以再配合数据库的存储过程,简单粗暴点的是把数据拉回来后代码多次循环处理。下面我们用指针/引用再没有冗余列的情况下仅遍历一次原始数据实现省市区的嵌套输出。

开始之前我们先简单说明一下数据源(数据结构)以及期望的输出结果:

这里先简单说明一下数据结构,从行政区划代码上可以看出,省级别的后4位位0,市级别的后两位为0,且市级别的前2位等于所在省份的前两位,而区级别的前4位与所在市的前4位相同,因此我们可以把一个行政区划代码分为三部分,前两位是省份代码、中间两位是市代码、最后两位为区代码。也就是从行政区划代码上就可以知道节点的级别,归属(父节点),相当于数据表中增加了parentIdlevel

0x01 完整程序

先把完整的代码给出,有兴趣的可以不看后面的分析。如果觉得不方便的可以去gist中查看,gist地址:https://gist.github.com/yaxin-cn/43873178ab6b6347b0466d0c0a262780

代码语言:txt
AI代码解释
复制
<?php
$data = file_get_contents("http://preview.www.mca.gov.cn/article/sj/xzqh/2020/2020/202101041104.html");
preg_match_all('#<td class=xl\d+?>(<span.*?)?(\d+|[\x{4e00}-\x{9fa5}]+).*?</td>#u', $data, $matches);

$administratives = [];
$node = array(
    'id' => '',
    'name' => ''
);
$fixNode = array(
    'id' => '',
    'name' => '市辖区'
);
foreach ($matches[2] as $idx => $v) {
    if ($idx % 2 == 0) {
        $node = array(
            'id' => $v,
            'name' => ''
        );
        if (in_array($v, ['110000', '120000', '310000', '500000'])) {
            $v[3] = '1';
            $fixNode['id'] = $v;
        }
    } else if ($idx % 2 == 1) {
        $node['name'] = $v;
        $administratives[] = $node;
        
        if (in_array($v, ['北京市', '天津市', '上海市', '重庆市'])) {
            $administratives[] = $fixNode;
        }
    }
}
unset($node);

$root = array();
$nodeMap = array();

foreach ($administratives as $item) {
    $rawId = (string)$item['id'];
    $id = (int)$rawId;
    $provinceId = (int)($id / 10000);
    $cityId = ((int)($id / 100)) % 100;
    $districtId = $id % 100;

    if ($cityId === 0 && $districtId === 0) {
        // 省份信息
        $node = array(
            'Id' => $rawId,
            'Name' => $item['name'],
            'Cities' => []
        );
        $nodeMap[$id] = &$node;

        $root[] = &$node;
    } else if ($districtId === 0) {
        // 市信息
        $fullCityId = $provinceId * 10000 + $cityId * 100;
        $node = array(
            'Id' => $rawId,
            'Name' => $item['name'],
            'Districts' => []
        );
        $nodeMap[$fullCityId] = &$node;

        $provinceNode = &$nodeMap[$provinceId * 10000];
        $provinceNode['Cities'][] = &$node;
    } else {
        // 区信息
        $fullCityId = $provinceId * 10000 + $cityId * 100;
        $node = array(
            'Id' => $rawId,
            'Name' => $item['name'],
        );
        $cityNode = &$nodeMap[$fullCityId];

        $cityNode['Districts'][] = $node;
    }
    unset($node);
}

print_r($root);

0x02 代码分析

该算法的本质是用空间换时间,并且在遍历到每一个节点时都将其添加到一个ID到节点的映射,并且通过是指针(引用)到节点的,而如果该节点是某个节点的子节点的话,会直接用指针的方式附加到改节点的子节点中,这样后面对该节点修改后会直接体现到父节点上。下面我们详细分析上面的代码。

2.1 第一部分

第1~33行代码跟主逻辑并无关联,主要的作用是模拟从数据库拉取数据,生成一个二维数组。方便直接运行代码查看效果等,避免了建表的麻烦。当然你也可以建表并且将数据写入表中,然后使用程序拉取,这个也应该是现网运行的正常逻辑。

数据库表样例:

代码语言:txt
AI代码解释
复制
CREATE TABLE `t_locations` (
  `id` int unsigned NOT NULL DEFAULT '0',
  `name` varchar(100) NOT NULL DEFAULT ''
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

2.2 省节点

根据之前的分析,当市和区代码为0时,该节点为省份信息节点。第47行我们创建一个省份节点,包含所有后续结果需要的信息,且包含了市节点Cities的空数组。52行将节点添加到一个以节点ID(行政区划代码)为键的关联数组(映射表)中,并且是通过指针(引用)的方式添加的,之所以这么做是为了这后面是市和区做准备。第54行将节点添加到最终结果数组中,这样$root变量就是我们最终需要的值。

2.3 市节点

我们接下来分析市节点代码:

市节点的处理包含了整个算法的核心逻辑,也就是如何把当前市添加到正确的身份的Cities中。

首先,我们可以通过市代码得知该市所在省份的代码,有了代码我们就可以通过上一步的$nodeMap获取到省份节点,由于我们上一步存进去的省份信息是一个指针(引用),所以这一步中我们获取到的省份节点就是最终结果$root变量中的省份节点,因而对该节点的Cities进行操作也会体现在最终的结果变量$root中,而这也保证了我们最终生成结果的正确性。

2.4 区节点

理解了市节点添加的逻辑,就很容易理解区节点添加的逻辑了,处理重点就在于定位市节点上,由于都是指针(引用),所有操作均会直接作用到最终结果上,从而实现我们最终想要的结果。

0x03 总结

开发中指针(引用)绝不仅仅是提升性能、减少资源占用的手段,它也可以作为简化代码逻辑的一个手段。最后这里再抛出一个思考题,我们上面的逻辑能正常运行的一个前提是$administratives变量中是有顺序的,如果没有顺序应该如何处理呢?这个可以人怎能思考一下,思路也是非常有趣的。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
给大家分享一个省市区选择框_js实现
=================================================
Hongten
2018/09/13
2.8K0
给大家分享一个省市区选择框_js实现
Java8编程小技巧,提高代码效率100%!超级实用!
大家好,我是小义,今天分享几个Java8编程小技巧,提高代码逼格,写出优雅代码,让同事看了也直呼内行。
程序员小义
2024/05/20
1870
Java8编程小技巧,提高代码效率100%!超级实用!
史上最全知识图谱建模实践(上):本体结构与语义解耦
在“无需复杂图谱术语,7个原则搞定Schema建模”一文中,我们总结了知识建模最佳实践的7个指导原则。本文中,我们将分基础篇、进阶篇,针对不同业务场景的建模需求,由浅及深讲解基于SPG的知识建模的方法和案例,并涉及术语的解释。
可信AI进展
2024/01/26
3.4K0
史上最全知识图谱建模实践(上):本体结构与语义解耦
腾讯地图获取全国行政区划检索列表Demo
全国行政区划检索功能, 由于高德和百度也没有提供一个比较完美的解决方案, 因此使用了腾讯地图iOS SDK内部封装的Web接口来实现. 行政区划共分为三个等级, 省级/市级/区级, 对于北京市和天津市这样的城市, 通常直接认为是省级, 并直接以同样的内容来填充市级. 但是SDK内部并没有提供这样的填充, 因此需要自行再省级里面将其复制到市级。
腾讯位置服务
2020/09/18
1.7K0
2021年国庆你的朋友去哪浪了?让Python告诉你!
国庆假期已经过半,你是出去浪了?还是在家里宅着呢?那你知道你的朋友去哪浪了吗?本文我们通过爬取去哪网售票数据(piao.qunar.com)来简单分析一下。
Python小二
2022/08/24
2970
2021年国庆你的朋友去哪浪了?让Python告诉你!
省市区联动
HTML: 1 <div class="china"> 2 <select name="" id="province"></select> 3 <select name="" id="city"></select> 4 <select name="" id="area"></select> 5 </div> CSS: 1 .chin
ProsperLee
2018/10/24
13K0
省市区联动
hhdb客户端介绍(11)
根据数据库管理软件项目接口要求,完善规范化接口对接内容,结合本次项目的具体建设目标,对以后的第三方接口开发交互提供指导建议。
恒辉信达
2024/12/16
720
【随笔】《全国车牌与地区数据表设计分享:从车牌前缀到行政地区全覆盖》
该表存储全国最详细的行政区划数据,包含邮编、区号、经纬度等信息,数据量较大(约 70 万条)。
框架师
2025/02/06
850
1-3 云商城环境准备和数据库表结构
  在商城系统中我们会使用到很多基础环境,比如MySQL数据库、Nacos注册中心、Redis数据库等、这些我们都会安装在Docker容器中。所以接下来我们搭建下基础环境
用户4919348
2021/01/13
4230
1-3 云商城环境准备和数据库表结构
从国家统计局官网获取最新省市区三级联动数据
目前从国家统计局官网找到的最新的县及县以上行政区划代码:http://www.stats.gov.cn/tjsj/tjbz/xzqhdm/201608/t20160809_1386477.html 可
晓晨
2018/06/22
1.5K0
原来炫酷的可视化地图,用Python就能搞定!
项目地址:https://gitee.com/jixuanfan/Map-of-China
小F
2020/11/19
1.3K0
原来炫酷的可视化地图,用Python就能搞定!
全国省市区县乡镇街道行政区划数据
markbob专栏
2023/07/18
9790
实战|省市区三级联动数据爬取
最近收到客服反应,系统的省市区数据好像不准,并且缺了一些地区。经过询问同事得知,数据库内的数据是从老项目拷贝过来的,有些年头了。难怪会缺一些数据。正好最近在对接网商银行,发现网商提供了省市区的数据的接口。这就很舒服了哇,抄起键盘就是干,很快的就把同步程序写好了。
不一样的科技宅
2021/01/16
2.3K0
实战|省市区三级联动数据爬取
【Html.js——数据整理】平地起高楼(蓝桥杯真题-2328)【合集】
在实际开发中,由于省市区等层级较多,使得数据结构按照嵌套关系来存储则过于复杂,一般在数据库中会将省市区数据解耦,每条信息以并列关系存储在一张表中,结构如下:
Rossy Yan
2025/02/02
780
【Html.js——数据整理】平地起高楼(蓝桥杯真题-2328)【合集】
我的第11个项目:爬取全国3177个城市​及对应编码
你好,我是zhenguo 这是我的第505篇原创文章 同时作为我的第11个项目:爬取全国城市和编码并数据分析 此系列过往10个项目都在这里: 我的第十个项目:开发一个Pygame经典小游戏 我的第九个项目:表情查询web工具 我的第八个项目:做一个web版停用词下载器 我的第七个项目:做一个web版记事本 我的第六个项目:实现一个任意图片下载器 我的第五个项目:实现一个文本定位器 我的第四个项目:Python自动生成密码 爬取网易云音乐每日推荐歌单,然后定时自动发送到朋友邮箱 我的第二个Python趣味
double
2022/03/21
8630
专家 x 抽象 x 类比
多年以前,我一直对于 “专家” 这一词有大量的困惑。到底怎样才是专家?怎样才算是技术专家?社交媒体上所谓的 “技术专家”,在某方面(如编程)上的实力一般,也算是专家吗?过去,我并没有细入的思考过这个问题,直到看到一个软件的元模型,以及一本名为《表象与本质》的书,才重新构建起一个专家的雏形 —— 感谢公司大佬之前推荐的 GEB。 在这里,便尝试性地做出第一次小结。作为第一次小结,它会存在一系列的不完善的地方,有待于后续进行完善。 所谓的专家嘛,就是在擅长的 “领域”(或者领域中的一个子领域)里,构建了具有范畴
Phodal
2022/04/19
4930
Flutter 多端天气预报APP第二弹 —— 城市定位以及城市代码的转换
在获取当前位置的过程中,我们使用了Flutter的Geolocator库。这个库不仅仅可以获取设备的经纬度,还能提供更多有关设备位置的信息。例如,我们可以获取设备的海拔高度、速度、方向等。在实际应用中,根据需求可以灵活运用这些功能,比如实现高度相关的气象应用或运动追踪应用等。下面是获取当前位置的代码:
繁依Fanyi
2024/03/20
2610
Flutter 多端天气预报APP第二弹 —— 城市定位以及城市代码的转换
这是一篇很务正业的可视化推送~(上篇)
自带学习R语言以来,从来没用把这些技能用在自己的专业方向上,说好的学以致用呢~ 最近看到的一篇微信公众号推文,内容是关于山东省各县(细化到137个县级行政区)2016年的GDP规模、公共预算收入规模及其增速指标,数据质量还不错,是山东省发改委公布的。 http://mp.weixin.qq.com/s/Sk4fIh3-ykcNK8uP0gZryw 感觉自己终于离专业方向近了一些(本人学财政的),数据就在眼前,这次机会一定要抓住了。 数据虽然质量不错,但是苦于手头没有最新的山东省县级地图素材(之前练习用的SH
数据小磨坊
2018/04/11
7090
地址管理之省市区三级联动菜单
地址管理之省市区三级联动菜单 三级联动表单 导入省市区的数据 下载sql语句的文件 在数据库中执行:source 文件路径即可导入 导入成功之后,在数据库中会出现三张表,分别代表省,市,区 创建实体类
爱撒谎的男孩
2018/05/25
4.2K1
【愚公系列】2022年08月 微信小程序-省市区三联动功能实现
多级联动下拉菜单是前端常见的效果,省市区三级联动又属于其中最典型的案例。多级联动一般都是与数据相关联的,根据数据来生成和修改联动的下拉菜单。完成一个多级联动效果,有助于增强对数据处理的能力。
愚公搬代码
2022/09/26
3.6K0
【愚公系列】2022年08月 微信小程序-省市区三联动功能实现
推荐阅读
相关推荐
给大家分享一个省市区选择框_js实现
更多 >
领券
💥开发者 MCP广场重磅上线!
精选全网热门MCP server,让你的AI更好用 🚀
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档