拧螺丝需求:递归算法的极致应用

前言

在一个平平无奇的下午,接到一个需求,需要给公司的中台系统做一个json报文重组的功能。
因为公司的某些业务需要外部数据的支持,所以会采购一些其它公司的数据,而且为了保证业务的连续性,同一种数据会采购多方的数据源
在这里插入图片描述
这里就出现了一个问题:

1.每个数据源的返回报文并不是一样的,所以需要在中台去进行转换,将不同数据源返回数据的结构重新组合
在这里插入图片描述

1.需求分析

首先,返回数据的格式为JSON,需要对原始数据的结构进行重组,也就是将原报文的值,放到新报文中,我将这个功能点拆成了两点:

① 取出原报文的值

② 构建新报文并将原报文的值放进去

根据上面这两点,我一下就想到使用递归算法来完成这个功能点

我们来看看递归算法是什么

递归算法

1.递归的基本思想:将一个大问题分解为若干个小问题,每个小问题都和原问题类似,但规模更小,直到最终问题可以轻易地被解决。

2.递归的终止条件:递归算法必须有一个明确的终止条件,否则算法将无限递归下去,导致程序崩溃。

3.递归的调用方式:在递归算法中,每次递归调用都会将问题的规模缩小,并将结果传递给下一次递归调用,直到最终得到问题的解。

4.递归的优势和劣势:递归算法可以使代码更加简洁清晰,同时也能够更自然地表达数学和物理模型等自然现象。但是,递归算法也存在一些劣势,比如可能会出现栈溢出等问题,同时递归算法的性能通常也不如迭代算法。

2.取出原报文的值

配置信息

首先,我们使用 . 来区分层级

例如:
在这里插入图片描述
这里我们注意三点:

1.判断原报文的节点为JSONArray还是JSONObject

2.是否为最后一层

3.要有明确中断条件,这里我们中断条件就是sourceKey不包含. 也就是挖掘报文到达了配置的最后一层

private static JSONObject getSourceJSON(Object obj, String sourceKey) {JSONObject result = new JSONObject();//如果最后一层则没有.if (!sourceKey.contains(".")) {result.put("keyName", sourceKey);result.put("data", obj);} else {//否则就不断向下递归//取出配置项中的第一节点,每一次递归,我们的第一节点也在这一层被消耗String tmpKey = sourceKey.substring(0, sourceKey.indexOf(" ."));String sourceKeyAfter = sourceKey.substring(sourceKey.indexOf(". ") + 1, sourceKey.length());String keyName = sourceKey.substring(sourceKey.lastIndexOf(".") + 1, sourceKey.length());//判断报文的数据类型if (obj instanceof JSONArray) {JSONArray ja = (JSONArray) obj;JSONArray tmpJA = new JSONArray();for (int i = 0; 1 < ja.size(); i++) {JSONObject jo = ja.getJSONObject(i);//不断向下挖掘JSONObject tmpJO = getSourceJSON(jo.get(tmpKey), sourceKeyAfter);Object o = tmpJO.get("data");if (o instanceof JSONArray) {JSONArray array = (JSONArray) o;for (int j = 0; j < array.size(); j++) {tmpJA.add(array.get(j));}} else {tmpJA.add(o);}}result.put("keyName", keyName);result.put("data", tmpJA);} else if (obj instanceof JSONObject) {JSONObject jo = (JSONObject) obj;return getSourceJSON(jo.get(tmpKey), sourceKeyAfter);}}return result;}

最后返回的是一个JSONObject,里面有两个key

① keyName:节点名称

② data:源数据

目的就是通过keyName能保证能从data直接取出数据

验证例子:

我们直接拿上面的JSON报文来进行演示,获取报文中url片段

String source = "{\"sites\":{\"site\":[{\"id\":\"1\",\"name\":\"baidu\",\"url\":\"www.baidu.com\"},{\"id\":\"2\",\"name\":\"Java\",\"url\":\"www.java.com\"},{\"id\":\"3\",\"name\":\"Google\",\"url\":\"www.google.com\"}]}}";
JSONObject sourceJSON = JSONObject.parseObject(source);
//直接打印结果
System.out.println(getSourceJSON(sourceJSON, "sites.site.url"));

输出:
在这里插入图片描述
通过keyName,判断data中的数据格式,JSONObject直接获取,JSONArray循环获取,这样我们就可以拿到url的值了

构建新报文并赋值

这也是一层层的构建,最后返回一整个重构后的报文,依旧使用我们的递归算法

由于是一层层,所以我们针对每一层,都需要配置它的数据类型

先给出配置
在这里插入图片描述
我们将此配置放到Map里,结构如下

JSONObject jo1 = new JSONObject(),jo2 = new JSONObject(),jo3 = new JSONObject(),jo4 = new JSONObject(),jo5 = new JSONObject();
jo1.put("type", "array");
jo1.put("sourceKey", "");
map.put("data", jo1);jo2.put("type", "array");
jo2.put("sourceKey", "");
map.put("data.baseInfo", jo2);jo3.put("type", "array");
jo3.put("sourceKey", "sites.site.id");
map.put("data.baseInfo.newid", jo3);jo4.put("type", "array");
jo4.put("sourceKey", "sites.site.name");
map.put("data.baseInfo.newname", jo4);jo5.put("type", "array");
jo5.put("sourceKey", "sites.site.url");
map.put("data.baseInfo.newurl", jo5);

map的key为目标构建路径,value为JSONObject,里面包含 ① 数据类型 ② 源路径

构建新报文的代码,需要注意以下几点

① 只有在最后一层才进行构建报文+赋值,前面全为构建

② 在构建之前判断节点是否存在,存在直接取出来进行递归,不存在再根据类型创建新节点

==③ 要有明确中断条件,这里我们中断条件就是targetKey不包含. ==

public static Object rebuildJSON(String targetKey, Object obj, Map<String, JSONObject> map, Object sourceObj,String sourceKey, String oldKey) {Object result = null;if (targetKey.contains(".")) {String tmpkey = targetKey.substring(0, targetKey.indexOf("."));String tmpkeyType = "array";if ("".equals(oldKey)) {tmpkeyType = map.get(tmpkey).getString("type");} else {tmpkeyType = map.get(oldKey + "." + tmpkey).getString("type");}String afterkey = targetKey.substring(targetKey.indexOf(".") + 1, targetKey.length());if (obj instanceof JSONArray) {JSONArray ja = (JSONArray) obj;JSONArray newJA = new JSONArray();if (ja.size() > 0) {for (int i = 0; i < ja.size(); i++) {JSONObject jo = ja.getJSONObject(i);Object tmpO = jo.get(tmpkey);if (tmpO == null) {if ("array".equals(tmpkeyType)) {JSONArray tmpja = new JSONArray();jo.put(tmpkey, tmpja);} else if ("object".equals(tmpkeyType)) {JSONObject tmpjo = new JSONObject();jo.put(tmpkey, tmpjo);}}tmpO = rebuildJSON(afterkey, jo.get(tmpkey), map, sourceObj, sourceKey, tmpkey);jo.put(tmpkey, tmpO);newJA.add(jo);}} else {JSONObject jo = new JSONObject();if ("array".equals(tmpkeyType)) {JSONArray tmpja = new JSONArray();jo.put(tmpkey, tmpja);} else if ("object".equals(tmpkeyType)) {JSONObject tmpjo = new JSONObject();jo.put(tmpkey, tmpjo);}Object tmpO = rebuildJSON(afterkey, jo.get(tmpkey), map, sourceObj, sourceKey, tmpkey);jo.put(tmpkey, tmpO);newJA.add(jo);}result = newJA;} else if (obj instanceof JSONObject) {JSONObject jo = (JSONObject) obj;JSONObject newJo = jo;Object tmpO = jo.get(tmpkey);if (tmpO == null) {if ("array".equals(tmpkeyType)) {JSONArray tmpja = new JSONArray();jo.put(tmpkey, tmpja);} else if ("object".equals(tmpkeyType)) {JSONObject tmpjo = new JSONObject();jo.put(tmpkey, tmpjo);}}tmpO = rebuildJSON(afterkey, jo.get(tmpkey), map, sourceObj, sourceKey, tmpkey);newJo.put(tmpkey, tmpO);result = newJo;}} else {if (obj instanceof JSONArray) {JSONArray ja = (JSONArray) obj;JSONArray sourceja = (JSONArray) sourceObj;JSONArray newJA = new JSONArray();if (sourceja.size() > ja.size()) {for (int i = 0; i < sourceja.size(); i++) {JSONObject targetJO;if (ja.size() > i) {targetJO = ja.getJSONObject(i);} else {targetJO = new JSONObject();}JSONObject sourceJO = sourceja.getJSONObject(i);targetJO.put(targetKey, sourceJO.get(sourceKey));newJA.add(targetJO);}} else {for (int i = 0; i < ja.size(); i++) {if (sourceja.size() > i) {JSONObject targetJO = ja.getJSONObject(i);JSONObject sourceJO = sourceja.getJSONObject(i);targetJO.put(targetKey, sourceJO.get(sourceKey));newJA.add(targetJO);}}}result = newJA;} else {JSONObject jo = (JSONObject) obj;JSONObject sourcejo = (JSONObject) sourceObj;jo.put(targetKey, sourcejo.get(sourceKey));result = jo;}}return result;}

测试代码:

public static void main(String[] args) {String source = "{\"sites\":{\"site\":[{\"id\":\"1\",\"name\":\"baidu\",\"url\":\"www.baidu.com\"},{\"id\":\"2\",\"name\":\"Java\",\"url\":\"www.java.com\"},{\"id\":\"3\",\"name\":\"Google\",\"url\":\"www.google.com\"}]}}";JSONObject sourceJSON = JSONObject.parseObject(source);Map<String,JSONObject> map = new HashMap<>();JSONObject jo1 = new JSONObject(),jo2 = new JSONObject(),jo3 = new JSONObject(),jo4 = new JSONObject(),jo5 = new JSONObject();jo1.put("type", "array");jo1.put("sourceKey", "");map.put("data", jo1);jo2.put("type", "array");jo2.put("sourceKey", "");map.put("data.baseInfo", jo2);jo3.put("type", "object");jo3.put("sourceKey", "sites.site.id");map.put("data.baseInfo.newid", jo3);jo4.put("type", "object");jo4.put("sourceKey", "sites.site.name");map.put("data.baseInfo.newname", jo4);jo5.put("type", "object");jo5.put("sourceKey", "sites.site.url");map.put("data.baseInfo.newurl", jo5);Object result = new JSONObject();for(Map.Entry<String,JSONObject> entry : map.entrySet()) {String sourceKey = entry.getValue().getString("sourceKey");//源路径为空我们不获取它的原值if("".equals(sourceKey)) {continue;}JSONObject sourceObj = getSourceJSON(sourceJSON, sourceKey);result = rebuildJSON(entry.getKey(), result, map, sourceObj.get("data"), sourceObj.getString("keyName"), "");}System.out.println(result);}

测试输出结果:
在这里插入图片描述
到这一步螺丝终于拧完了!

这个只能针对标准的JSON报文去处理,在这一步前我还利用了其它的算法将不标准的报文转化为标准的,详细代码关注我后续会讲解

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/1775.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Qt QSqlQueryModel详解

背景知识&#xff1a; Qt SQL的API分为不同层&#xff1a; 驱动层 驱动层 对于QT是基于C来实现的框架&#xff0c;该层主要包括QSqlDriver、QSqlDriverCreator、QSqlDriverCreatorbase、QSqlDriverPlugin and QSqlResult。这一层提供了特定数据库和SQL API层之间的底层桥梁…

Servlet(下篇)

哥几个来学 Servlet 啦 ~~ 这个是 Servlet&#xff08;上篇&#xff09;的链接&#xff0c; (2条消息) Servlet &#xff08;上篇&#xff09;_小枫 ~的博客-CSDN博客https://blog.csdn.net/m0_64247824/article/details/131229873主要讲了 Servlet的定义、Servlet的部署方式、…

C语言-基础语法学习-3 二级指针

目录 二级指针二级指针的定义和声明二级指针的初始化二级指针的使用二级指针和函数参数二级指针和动态内存分配数组指针二维数组二维数组的初始化二维数组与指针二维数组的遍历 二级指针 当涉及到多级指针时&#xff0c;C语言的灵活性和强大的指针功能可以得到充分的发挥。二级…

原生HTML+CSS+JS制作自己的导航主页

如果你想使用原生HTML、CSS和JS制作自己的导航主页&#xff0c;你可以按照以下步骤进行操作&#xff1a; 先看效果图&#xff1a; 创建HTML文件&#xff1a;首先&#xff0c;创建一个新的HTML文件&#xff0c;并在文件中添加基本的HTML结构。你可以使用<!DOCTYPE html>…

R语言复现一篇6分的孟德尔随机化文章

上一期我们对孟德尔随机化做了一个简单的介绍&#xff0c;今天我们来复现一篇6分左右的使用了孟德尔随机化方法的文章&#xff0c;文章的题目是&#xff1a;Mendelian randomization analysis does not reveal a causal influence of mental diseases on osteoporosis&#xff…

基于tensorflow深度学习的猫狗分类识别

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

排序算法——归并排序(递归与非递归)

归并排序 以升序为例 文章目录 归并排序基本思想核心步骤递归写法实现代码 非递归处理边界情况实现代码 时间复杂度 基本思想 归并排序是建立在归并操作上的一种有效的排序算法&#xff0c;该算法是采用分治法的一个非常典型的应用&#xff1a;将已有序的子序列合并&#xff…

《C++ Primer》--学习7

顺序容器 容器库概览 迭代器 与容器一样&#xff0c;迭代器有着公共的接口&#xff1a;如果一个迭代器提供某个操作&#xff0c;那么所有提供相同操作的迭代器对这个操作的实现方式都是相同的。 迭代器范围 一个迭代器范围是由一对迭代器表示&#xff0c;两个迭代器分别指向…

IM即时通讯APP在聊天场景中的应用

即时通讯&#xff08;IM&#xff09;应用可以满足人们随时随地进行文字、语音、图片、视频等多媒体信息的传递需求&#xff0c;为个人和企业提供了高效、便捷的沟通方式。在企业中&#xff0c;IM即时通讯APP更是发挥着重要的作用&#xff0c;促进了协作和团队工作的效率提升。以…

项目——学生信息管理系统3

目录 班级添加的界面实现 创建班级的实体类 在org.xingyun.dao 包下 编写 ClassDao 创建 AddStudentClassFrm 添加班级页面 注意创建成 JInternalFrame 类型 给控件起个名字 注释掉main方法 给提交按钮绑定事件 回到 MainFrm.java 给添加班级按钮绑定事件 启动测试 班…

基于卡尔曼滤波进行四旋翼动力学建模(SimulinkMatlab)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

网络安全实战植入后门程序

在 VMware 上建立两个虚拟机&#xff1a;win7 和 kali。 Kali&#xff1a;它是 Linux 发行版的操作系统&#xff0c;它拥有超过 300 个渗透测试工具&#xff0c;就不用自己再去找安装包&#xff0c;去安装到我们自己的电脑上了&#xff0c;毕竟自己从网上找到&#xff0c;也不…