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

news2024/11/25 23:03:25

前言

在一个平平无奇的下午,接到一个需求,需要给公司的中台系统做一个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.coloradmin.cn/o/704972.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

电子模块|航空插头简介

电子模块|航空插头简介 航空插头图片航空插头介绍为什么要用航插航空插头实例及参数 航空插头图片 航空插头介绍 航空插头定义&#xff1a; 它是针对复杂工业环境与户外环境等应用场景开发的一类连接器。正式一些的称呼是“工业连接器”&#xff0c;主要用于电气、电子设备的电…

react菜鸟教程学习笔记

目录 第一个react实例 react安装 对react机制最直观的理解 如果你第一次用npm 关于初始化package.json的问题 使用 create-react-app 快速构建 React 开发环境 项目目录结构 修改一下代码执行源头APP.js React元素渲染 将元素渲染到DOM中 更新元素渲染 关于vue的更新…

Dlib —— 对图片进行人脸检测(附C++源码)

效果 注意&#xff1a;Dlib检测人脸在Release版耗时与CPU有关,本人I7 10代约100ms左右。建议人脸检测可以考虑使用Yolov5进行&#xff0c;之后将检测到的人脸输入给Dlib做特征或其他。 代码 Vs2017下使用Dlib检测人脸&#xff0c;并通过OpenCv将结果绘制出来。&#xff08;由于…

推荐几个数据可视化工具汇总

数据的魅力在于其故事性和洞察力。让数据说话&#xff0c;我们汇集了一系列令人兴奋的数据可视化工具&#xff0c;为您提供展示和探索数据的无限可能。 分享一&#xff1a;Tangle Tangle是一个基于Web的数据可视化工具&#xff0c;旨在帮助大家以交互式和可视化的方式探索和解…

使用chatgpt过funcaptcha验证码2个人学习记录

funcaptcha 验证码2 通过记录 ** funcaptcha 那个公司开发的简要介绍&#xff1a; Funcaptcha是由hCaptcha公司开发的一种人机验证系统。hCaptcha是一家位于美国的人机验证技术提供商&#xff0c;旨在帮助网站和应用程序防止自动化攻击和滥用。 Funcaptcha是hCaptcha提供的一种…

MYSQL 数据清理磁盘没变小问题解决方法

我们到数据目录查看有些表比较大&#xff0c;清理了一些无用数据后发现&#xff0c;文件大小不变。这是mysql的机制导致的。 解决方法&#xff1a;重建索引释放空间。 alter table $TABLE engineInnoDB;

接口测试的流程

目录 前言&#xff1a; 接口测试流程 接口测试用例设计 接口测试工具 前言&#xff1a; 接口测试是软件测试中的一个关键环节&#xff0c;用于验证系统的各个接口是否符合预期功能和性能要求。 接口通俗的理解就是不同部分之间的连接通道&#xff0c;可以是程序之内的&am…

原码、反码及补码

任何存储于计算机中的数据&#xff0c;其本质都是以二进制码存储。计算机的运算器只有加法运算器。所以在计算机中没办法直接做减法。 从硬件的角度来说正数正数、负数负数都是可以通过加法器直接相加&#xff0c;只有正数加负数才算是减法。原码、反码及补码的产生过程就是为…

HOT30-两两交换链表中的节点

leetcode原题链接&#xff1a;两两交换链表中的节点 题目描述 给你一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题&#xff08;即只能进行节点交换&#xff09;。 示例 1&#xff1a; 输入&a…

0055. 跳跃游戏

0055. 跳跃游戏 原题链接&#xff1a;完成情况&#xff1a;解题思路&#xff1a;参考代码&#xff1a;__55跳跃游戏01__动态规划__55跳跃游戏01__贪心 原题链接&#xff1a; 0055. 跳跃游戏 https://leetcode-cn.com/problems/jump-game/ 完成情况&#xff1a; 解题思路&…

MySql学习2:SQL分类、数据库操作、表操作、数据的增删改查

SQL分类 SQL分类&#xff1a; DDL&#xff1a;数据定义语言&#xff0c;用来定义数据库对象&#xff08;数据库、表、字段&#xff09;DML&#xff1a;数据操作语言&#xff0c;用来对数据库表中的数据进行增删改DQL&#xff1a;数据库查询语言&#xff0c;用来查询数据库表中…

jsp SSM宠物网站系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 jsp 宠物网站系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,eclipse开发&#xff0c;数据库为Mysql5.0&#xff0…

JavaScript 中有趣的 9 个常用编码套路

大厂面试题分享 面试题库 前后端面试题库 &#xff08;面试必备&#xff09; 推荐&#xff1a;★★★★★ 地址&#xff1a;前端面试题库 web前端面试题库 VS java后端面试题库大全 我今天仔细研究了一下掘金上的热门文章数据和内容。我发现你们真是热衷于学习&#xff0c;喜…

#10045. 「一本通 2.2 练习 1」Radio Transmission(内附封面)

[BOI2009] Radio Transmission 无线传输 题目描述 给你一个字符串 s 1 s_1 s1​&#xff0c;它是由某个字符串 s 2 s_2 s2​ 不断自我连接形成的&#xff08;保证至少重复 2 2 2 次&#xff09;。但是字符串 s 2 s_2 s2​ 是不确定的&#xff0c;现在只想知道它的最短长度…

springboot流浪动物救助系统-计算机毕设 附源码78174

springboot流浪动物救助系统 摘 要 21世纪的今天&#xff0c;随着社会的不断发展与进步&#xff0c;人们对于信息科学化的认识&#xff0c;已由低层次向高层次发展&#xff0c;由原来的感性认识向理性认识提高&#xff0c;管理工作的重要性已逐渐被人们所认识&#xff0c;科学…

目标检测算法-YOLOV8解析(附论文和源码)

目标检测算法-YOLOV8解析&#xff08;附论文和源码&#xff09;

LeetCode刷题 | 300. 最长递增子序列、674. 最长连续递增序列、718. 最长重复子数组

300. 最长递增子序列 给你一个整数数组 nums &#xff0c;找到其中最长严格递增子序列的长度。 子序列 是由数组派生而来的序列&#xff0c;删除&#xff08;或不删除&#xff09;数组中的元素而不改变其余元素的顺序。例如&#xff0c;[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子…

地图可视化开发的平台如何选择?

地图数据的日益丰富和人们对数据可视化需求不断提高&#xff0c;地图可视化已经成为了信息化建设中重要的组成部分&#xff0c;在各个行业和领域中都有广泛的应用。地图可视化开发平台选择至关重要&#xff0c;不仅会影响到可视化效果&#xff0c;还会影响到开发难度、维护成本…

我国没有根服务器,那么别人可以控制中国的网络吗?

服务器没想象的那么重要。 根服务器简单理解就是一个密码对应一个访问地址。 就像小时候座机电话刚兴起的时候&#xff0c;那时候给有座机的每家都会发一个全市各部门的联系电话的通讯录。 而发布这个电话通讯录的地方就类似根服务器的作用。 然后每家都自己弄一本一样的&am…

AMEYA360:太阳诱电导电性高分子混合铝电解电容器

太阳诱电导电性高分子混合铝电解电容器&#xff0c;最适合需要大容量和高耐压的车载装置和产业设备。电解质使用导电性高分子和电解液&#xff0c;兼具高性能和高可靠性&#xff0c;满足客户需求。 混合结构在阳极箔表面生成电介质(氧化铝)。用隔膜隔开阳极箔与阴极箔&#xff…