js处理扁平数组和树结构相互转换
一、将扁平的数据转为树形结构
在 js中,可以使用递归算法将扁平的数据转换为树形结构。
扁平数据通常是一个带有 parentId 属性的数组,而树形结构通常是一个带有 children 属性的对象。
1、方法一
下面是一个简单的例子,演示如何将扁平数组转换为树形对象:
let data = [{ id: 1, pid: 0, name: '中国' },{ id: 2, pid: 0, name: '巴铁' },{ id: 3, pid: 1, name: '小日本儿' },{ id: 4, pid: 2, name: '杂种美国' },{ id: 5, pid: 2, name: '俄罗斯' },{ id: 6, pid: 13, name: '乌克兰' },{ id: 7, pid: 3, name: '英国' },{ id: 8, pid: 7, name: '意大利' },{ id: 9, pid: 7, name: '西班牙' }
];function convertToTree(flatData) {let treeData = [];let map = new Map(); let outputObj, pid;for (let i = 0; i < flatData.length; i++) {pid = flatData[i].pid;if (map.has(pid)) {if (!map.get(pid).childrens)map.get(pid).childrens = [];let obj = new Object(flatData[i]);map.get(pid).childrens.push(obj);map.set(flatData[i].id, obj);} else if (!map.has(pid) && pid === 0) {// '&& pid === 0' 判断条件是为了只将 pid 为 0 作为根节点,其它值不作为根节点。// 如需将其它值也作为根节点,可将 'else if (!map.has(pid) && pid === 0)' 改为 'else'outputObj = new Object(flatData[i]);treeData.push(outputObj);map.set(flatData[i].id, outputObj);}}return treeData;
}let TreeData = convertToTree(data);
console.log(TreeData);
2、方法二
使用递归算法将扁平数组转换为树形对象:
const flatData = [{ id: 1, name: 'Node 1', parentId: null },{ id: 2, name: 'Node 2', parentId: 1 },{ id: 3, name: 'Node 3', parentId: 2 },{ id: 4, name: 'Node 4', parentId: 3 },{ id: 5, name: 'Node 5', parentId: 3 }
];function convertToTree(flatData, parentId = null) {const children = flatData.filter(node => node.parentId === parentId);if (!children.length) {return null;}return children.map(node => ({...node,children: convertToTree(flatData, node.id)}));
}const treeData = convertToTree(flatData);
console.log(treeData);
该算法的流程为:
- 使用 filter() 函数过滤出所有的子节点。
- 使用 map() 函数构造每个子节点的新结构,并使用递归来处理子节点的 children 属性。
3、方法三
还有一些第三方库可以帮助你转换扁平数据为树形结构,例如 lodash 中的 _.groupBy() 和 _.mapValues() 方法可以帮助你将扁平数据转换为树形数据。
const flatData = [{ id: 1, name: 'Node 1', parentId: null },{ id: 2, name: 'Node 2', parentId: null },{ id: 3, name: 'Node 3', parentId: 1 },{ id: 4, name: 'Node 4', parentId: 2 },{ id: 5, name: 'Node 5', parentId: 2 }
];const tree = _(flatData).groupBy('parentId').mapValues((children, parentId) => ({id: parentId || 'root',children: children.map(({ id, name, parentId }) => ({ id, name, parentId }))})).values().value();console.log(tree)
在这种情况下,假设parentId为null的数据项是根节点,那么所有其它的数据项的 parentId 分别对应它的父节点,我们可以使用 groupBy() 来将所有节点根据它们的 parentId 分组,然后我们可以使用 mapValues() 来构造每个组的新结构。
4、方法四
const flatData = [{ id: 1, name: 'Node 1', value: 1, parentId: null },{ id: 2, name: 'Node 2', value: 2, parentId: 1 },{ id: 3, name: 'Node 3', value: 3, parentId: 2 },{ id: 4, name: 'Node 4', value: 4, parentId: 3 },{ id: 5, name: 'Node 5', value: 5, parentId: 3 }
];/*** 将扁平数组转换为树形对象,* 适用于来自同一个表的数据,即idName的数据不重复* * @param {*} flatData 同级数组数据* @param {*} idName 唯一id* @param {*} pidName 父级id* @param {*} nameName 自定义(Cascader 级联选择器)键名称* @param {*} valueName 自定义(Cascader 级联选择器)值名称* @returns 树形结构数组数据,适用于Cascader 级联选择器组件*/
function convertToTree(flatData, idName, pidName, nameName, valueName) {let treeData = [];if (!Array.isArray(flatData)) {return treeData;}flatData.forEach((item) => {delete item.children;});let map = {};flatData.forEach((item) => {// 深拷贝,该方式将使该转换方法失效// map[item[idName]] = JSON.parse(JSON.stringify(item));// 浅拷贝,将对 item 的引用传递给 mapmap[item[idName]] = item;});flatData.forEach((item) => {// 深拷贝,该方式将使该转换方法失效// let parent = JSON.parse(JSON.stringify(map[item[pidName]]));// 浅拷贝,将对 map 的引用传递给 parentlet parent = map[item[pidName]];if (parent) {// 利用了浅拷贝的引用传递,最终 flatData 中的 item 将会改变(parent.children || (parent.children = [])).push(nameName && valueName ? Object.assign(item, { label: item[nameName], id: item[valueName] }) : item);} else {treeData.push(nameName && valueName ? Object.assign(item, { label: item[nameName], id: item[valueName] }) : item);}});return treeData;
}const treeData = convertToTree(flatData, 'id', 'parentId', 'name', 'value');
console.log(treeData);
二、树形转扁平
1、方法一
在 js中,可以使用递归算法将树形结构数据转换为扁平数组。
下面是一个简单的例子,它演示了如何将树形数据转换为扁平数组:
const treeData = [{id: 1,name: 'Node 1',children: [{ id: 2, name: 'Node 2', children: [{ id: 3, name: 'Node 3' }, { id: 4, name: 'Node 4' }] },{ id: 5, name: 'Node 5' }]
}];function convertToFlat(data, parentId = null) {return data.reduce((acc, curr) => {acc.push({ ...curr, parentId });if (curr.children) {acc = acc.concat(convertToFlat(curr.children, curr.id));}return acc;}, []);
}const flatData = convertToFlat(treeData);
console.log(flatData);
该算法的流程为:
- 使用 reduce() 函数遍历每个节点,并将父节点的 id 作为参数传递给递归函数。
- 使用 push() 函数将当前节点添加到结果数组中。
- 使用 concat() 函数将递归调用的结果与结果数组连接在一起。
- 如果当前节点有 children 属性,则递归调用 convertToFlat() 函数,并将当前节点的 id 作为父节点传递给函数。
注意:该方法返回的扁平结构数据未将 children属性删除,因此存在冗余的数据。
这是一种将树形结构数据转换为扁平数组的方法,如果有其他特定的需求,还可以使用其他方法来转换数据,例如使用广度优先遍历算法,使用队列存储节点。
2、方法二
const treeData = [{id: 1,name: 'Node 1',children: [{id: 2,name: 'Node 2',children: [{ id: 3, name: 'Node 3' },{ id: 4, name: 'Node 4' },]},{ id: 5, name: 'Node 5' },]},{id: 6,name: 'Node 6',children: [{ id: 7, name: 'Node 7' }]},
];function convertToFlat(treeData, parentId = null) {let flatData = [];for (let node of treeData) {flatData.push({ id: node.id, name: node.name, parentId });if (node.children) {flatData = flatData.concat(convertToFlat(node.children, node.id));}}return flatData;
}const flatData = convertToFlat(treeData);
console.log(flatData);
该算法的流程为:
- 创建一个空的扁平数组。
- 递归遍历树形数组中的每个节点,将当前节点添加到扁平数组中。
- 对于当前节点的子节点,继续使用递归,并将子节点添加到扁平数组中。
- 返回扁平数组
注意:该方法需要手动构造push 到扁平数组的对象,通用性较差。
3、方法三
在 js中,可以使用递归算法将树形结构数据转换为扁平数组。
下面是一个简单的例子,它演示了如何将树形数据转换为扁平数组:
let data = [{id: 1, pid: 0, name: '棒子', childrens: [{id: 2, pid: 1, name: '中国', childrens: [{ id: 4, pid: 2, name: '小日本儿' },{ id: 5, pid: 2, name: '杂种美国' }]},{id: 3, pid: 1, name: '俄罗斯', childrens: [{ id: 6, pid: 3, name: '巴铁' },{ id: 7, pid: 3, name: '阿三' }]}]
}];function convertToFlat(treeData) {let flatData = [];for (let i = 0; i < treeData.length; i++) {if (treeData[i].childrens) {flatData.push(...convertToFlat(treeData[i].childrens));delete treeData[i].childrens;}flatData.push({ ...treeData[i] });}return flatData;
}let flatData = convertToFlat(data);
console.log(flatData);
该方法通用性较强,对树形结构数组数据内部具体的属性名称要求较小(除 childrens)。
相关文章:
js处理扁平数组和树结构相互转换
一、将扁平的数据转为树形结构 在 js中,可以使用递归算法将扁平的数据转换为树形结构。 扁平数据通常是一个带有 parentId 属性的数组,而树形结构通常是一个带有 children 属性的对象。 1、方法一 下面是一个简单的例子,演示如何将扁平数…...
Spark弹性分布式数据集
1. Spark RDD是什么 RDD(Resilient Distributed Dataset,弹性分布式数据集)是一个不可变的分布式对象集合,是Spark中最基本的数据抽象。在代码中RDD是一个抽象类,代表一个弹性的、不可变、可分区、里面的元素可并行计…...
ffmpeg学习记录
1、对图片进行裁剪 ffmpeg -i input.jpg -vf cropiw/3:ih:20:0 caijian.jpg PS: crop100:100:12:34 相同效果: cropw100:h100:x12:y34 2、视频增加文字水印 使用drawtext滤镜进行增加水印 参数 类型 说明 text 字符串 文字 textfile 字符串 文字文件 …...
ChatGPT:为教育创新提供五大机遇
随着智能技术的不断发展,ChatGPT在教育场景中的创新价值可能比我们能够意识到的还要多。比如它可以自动处理作业、在线答疑,可以辅助语言学习、实时沟通,甚至还可以用于评估诊断、科学研究。国内外关于利用ChatGPT实现教育创新的场景描绘已经…...
Educational Codeforces Round 151 (Rated for Div. 2)
Edu 151 A. Forbidden Integer 题意: 你有[1, k]内除了 x x x的整数,每个数可以拿多次,问 ∑ n \sum n ∑n是否可行并构造 思路: 有1必能构造,否则假如没有1,假如有2, 3必定能构造出大于等于2的所有数&…...
【AI机器学习入门与实战】机器学习算法都有哪些分类?
👍【AI机器学习入门与实战】目录 🍭基础篇 🔥 第一篇:【AI机器学习入门与实战】AI 人工智能介绍 🔥 第二篇:【AI机器学习入门与实战】机器学习核心概念理解 🔥 第三篇:【AI机器学习入…...
React之hooks
Hooks函数 1.useState():状态钩子。纯函数组件没有状态,用于为函数组件引入state状态, 并进行状态数据的读写操作。 const [state, setState] useState(initialValue); // state:初始的状态属性,指向状态当前值,类似…...
1.监控分布式--zabbix
文章目录 监控分布式-zabbix、prometheus概念工作原理功能组件部署zabbix安装Nginx和PHP环境部署数据库编码安装zabbix编译安装zabbix server客户端安装zabbix agent服务 监控分布式-zabbix、prometheus 利用一个优秀的监控软件,我们可以: 通过一个友好的界面进行…...
java stream 多个集合去重取交集
文章目录 背景案例代码 背景 原因是需要从表里查多个集合list,然后取多个集合得交集,并且元素是对象,所以使用了下面的方式,当然方式有很多种,仅供参考。 案例 下面提供了一段多个集合join取交集的例子,…...
给LLM装上知识:从LangChain+LLM的本地知识库问答到LLM与知识图谱的结合
第一部分 什么是LangChain:连接本地知识库与LLM的桥梁 作为一个 LLM 应用框架,LangChain 支持调用多种不同模型,提供相对统一、便捷的操作接口,让模型即插即用,这是其GitHub地址,其架构如下图所示 (点此查…...
视频与AI,与进程交互(二) pytorch 极简训练自己的数据集并识别
目标学习任务 检测出已经分割出的图像的分类 2 使用pytorch pytorch 非常简单就可以做到训练和加载 2.1 准备数据 如上图所示,用来训练的文件放在了train中,验证的文件放在val中,train.txt 和 val.txt 分别放文件名称和分类类别ÿ…...
LLM - 第2版 ChatGLM2-6B (General Language Model) 的工程配置
欢迎关注我的CSDN:https://spike.blog.csdn.net/ 本文地址:https://blog.csdn.net/caroline_wendy/article/details/131445696 ChatGLM2-6B 是开源中英双语对话模型 ChatGLM-6B 的第二代版本,在保留了初代模型对话流畅、部署门槛较低等众多优…...
从0开始,手写MySQL事务
说在前面:从0开始,手写MySQL的学习价值 尼恩曾经指导过的一个7年经验小伙,凭借精通Mysql, 搞定月薪40K。 从0开始,手写一个MySQL的学习价值在于: 可以深入地理解MySQL的内部机制和原理,Mysql可谓是面试的…...
React中useState的setState方法请求了好多次
1、问题描述 最近在写react的时候碰到了一个很奇怪的问题。 可以看到那个getXXX()的方法一直不断的被调用,网页一直请求,根本停不下来了。 2、产生原因 要弄明白这个原因,首先要先了解一下react生命周期。 react是组件式的编程,一…...
【MYSQL基础】基础命令介绍
基础命令 MYSQL注释方式 -- 单行注释/* 多行注释 哈哈哈哈哈 哈哈哈哈 */连接数据库 mysql -u root -p12345678退出数据库连接 使用exit;命令可以退出连接 查询MYSQL版本 mysql> select version(); ----------- | version() | ----------- | 8.0.27 | ----------- 1…...
多元回归预测 | Matlab基于灰狼算法优化深度置信网络(GWO-DBN)的数据回归预测,matlab代码回归预测,多变量输入模型
文章目录 效果一览文章概述部分源码参考资料效果一览 文章概述 多元回归预测 | Matlab基于灰狼算法优化深度置信网络(GWO-DBN)的数据回归预测,matlab代码回归预测,多变量输入模型,matlab代码回归预测,多变量输入模型,多变量输入模型 评价指标包括:MAE、RMSE和R2等,代码质…...
校园wifi网页认证登录入口
很多校园wifi网页认证登录入口是1.1.1.1 连上校园网在浏览器写上http://1.1.1.1就进入了校园网 使 用 说 明 一、帐户余额 < 0.00元时,帐号被禁用,需追加网费。 二、在计算中心机房上机的用户,登录时请选择新建帐号时给您指定的NT域&…...
[SpringBoot]Spring Security框架
目录 关于Spring Security框架 Spring Security框架的依赖项 Spring Security框架的典型特征 关于Spring Security的配置 关于默认的登录页 关于请求的授权访问(访问控制) 使用自定义的账号登录 使用数据库中的账号登录 关于密码编码器 使用BCry…...
Unity 之 抖音小游戏本地数据最新存储方法分享
Unity 之 抖音小游戏本地数据最新存储方法分享 一、抖音小游戏文件存储系统背景二、文件存储系统的使用方法2.1 初始化2.1 创建目录2.3 存储数据2.4 删除目录/文件2.5 其他相关操作 三,小结 抖音小游戏是一种基于抖音平台开发的小型游戏,与传统的 APP 不…...
逍遥自在学C语言 | 函数初级到高级解析
前言 函数是C语言中的基本构建块之一,它允许我们将代码组织成可重用、模块化的单元。 本文将逐步介绍C语言函数的基础概念、参数传递、返回值、递归以及内联函数和匿名函数。 一、人物简介 第一位闪亮登场,有请今后会一直教我们C语言的老师 —— 自在…...
零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?
一、核心优势:专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发,是一款收费低廉但功能全面的Windows NAS工具,主打“无学习成本部署” 。与其他NAS软件相比,其优势在于: 无需硬件改造:将任意W…...
Spark 之 入门讲解详细版(1)
1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室(Algorithms, Machines, and People Lab)开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目,8个月后成为Apache顶级项目,速度之快足见过人之处&…...
树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频
使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...
反向工程与模型迁移:打造未来商品详情API的可持续创新体系
在电商行业蓬勃发展的当下,商品详情API作为连接电商平台与开发者、商家及用户的关键纽带,其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息(如名称、价格、库存等)的获取与展示,已难以满足市场对个性化、智能…...
AtCoder 第409场初级竞赛 A~E题解
A Conflict 【题目链接】 原题链接:A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串,只有在同时为 o 时输出 Yes 并结束程序,否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...
华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建
华为云FlexusDeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色,华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型,能助力我们轻松驾驭 DeepSeek-V3/R1,本文中将分享如何…...
现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?
现有的 Redis 分布式锁库(如 Redisson)相比于开发者自己基于 Redis 命令(如 SETNX, EXPIRE, DEL)手动实现分布式锁,提供了巨大的便利性和健壮性。主要体现在以下几个方面: 原子性保证 (Atomicity)ÿ…...
基于IDIG-GAN的小样本电机轴承故障诊断
目录 🔍 核心问题 一、IDIG-GAN模型原理 1. 整体架构 2. 核心创新点 (1) 梯度归一化(Gradient Normalization) (2) 判别器梯度间隙正则化(Discriminator Gradient Gap Regularization) (3) 自注意力机制(Self-Attention) 3. 完整损失函数 二…...
C#学习第29天:表达式树(Expression Trees)
目录 什么是表达式树? 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持: 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...
免费数学几何作图web平台
光锐软件免费数学工具,maths,数学制图,数学作图,几何作图,几何,AR开发,AR教育,增强现实,软件公司,XR,MR,VR,虚拟仿真,虚拟现实,混合现实,教育科技产品,职业模拟培训,高保真VR场景,结构互动课件,元宇宙http://xaglare.c…...
