当前位置: 首页 > news >正文

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中&#xff0c;可以使用递归算法将扁平的数据转换为树形结构。 扁平数据通常是一个带有 parentId 属性的数组&#xff0c;而树形结构通常是一个带有 children 属性的对象。 1、方法一 下面是一个简单的例子&#xff0c;演示如何将扁平数…...

Spark弹性分布式数据集

1. Spark RDD是什么 RDD&#xff08;Resilient Distributed Dataset&#xff0c;弹性分布式数据集&#xff09;是一个不可变的分布式对象集合&#xff0c;是Spark中最基本的数据抽象。在代码中RDD是一个抽象类&#xff0c;代表一个弹性的、不可变、可分区、里面的元素可并行计…...

ffmpeg学习记录

1、对图片进行裁剪 ffmpeg -i input.jpg -vf cropiw/3:ih:20:0 caijian.jpg PS&#xff1a; crop100:100:12:34 相同效果: cropw100:h100:x12:y34 2、视频增加文字水印 使用drawtext滤镜进行增加水印 参数 类型 说明 text 字符串 文字 textfile 字符串 文字文件 …...

ChatGPT:为教育创新提供五大机遇

随着智能技术的不断发展&#xff0c;ChatGPT在教育场景中的创新价值可能比我们能够意识到的还要多。比如它可以自动处理作业、在线答疑&#xff0c;可以辅助语言学习、实时沟通&#xff0c;甚至还可以用于评估诊断、科学研究。国内外关于利用ChatGPT实现教育创新的场景描绘已经…...

Educational Codeforces Round 151 (Rated for Div. 2)

Edu 151 A. Forbidden Integer 题意&#xff1a; 你有[1, k]内除了 x x x的整数&#xff0c;每个数可以拿多次&#xff0c;问 ∑ n \sum n ∑n是否可行并构造 思路&#xff1a; 有1必能构造&#xff0c;否则假如没有1&#xff0c;假如有2, 3必定能构造出大于等于2的所有数&…...

【AI机器学习入门与实战】机器学习算法都有哪些分类?

&#x1f44d;【AI机器学习入门与实战】目录 &#x1f36d;基础篇 &#x1f525; 第一篇&#xff1a;【AI机器学习入门与实战】AI 人工智能介绍 &#x1f525; 第二篇&#xff1a;【AI机器学习入门与实战】机器学习核心概念理解 &#x1f525; 第三篇&#xff1a;【AI机器学习入…...

React之hooks

Hooks函数 1.useState()&#xff1a;状态钩子。纯函数组件没有状态&#xff0c;用于为函数组件引入state状态, 并进行状态数据的读写操作。 const [state, setState] useState(initialValue); // state&#xff1a;初始的状态属性&#xff0c;指向状态当前值&#xff0c;类似…...

1.监控分布式--zabbix

文章目录 监控分布式-zabbix、prometheus概念工作原理功能组件部署zabbix安装Nginx和PHP环境部署数据库编码安装zabbix编译安装zabbix server客户端安装zabbix agent服务 监控分布式-zabbix、prometheus 利用一个优秀的监控软件&#xff0c;我们可以: 通过一个友好的界面进行…...

java stream 多个集合去重取交集

文章目录 背景案例代码 背景 原因是需要从表里查多个集合list&#xff0c;然后取多个集合得交集&#xff0c;并且元素是对象&#xff0c;所以使用了下面的方式&#xff0c;当然方式有很多种&#xff0c;仅供参考。 案例 下面提供了一段多个集合join取交集的例子&#xff0c;…...

给LLM装上知识:从LangChain+LLM的本地知识库问答到LLM与知识图谱的结合

第一部分 什么是LangChain&#xff1a;连接本地知识库与LLM的桥梁 作为一个 LLM 应用框架&#xff0c;LangChain 支持调用多种不同模型&#xff0c;提供相对统一、便捷的操作接口&#xff0c;让模型即插即用&#xff0c;这是其GitHub地址&#xff0c;其架构如下图所示 (点此查…...

视频与AI,与进程交互(二) pytorch 极简训练自己的数据集并识别

目标学习任务 检测出已经分割出的图像的分类 2 使用pytorch pytorch 非常简单就可以做到训练和加载 2.1 准备数据 如上图所示&#xff0c;用来训练的文件放在了train中&#xff0c;验证的文件放在val中&#xff0c;train.txt 和 val.txt 分别放文件名称和分类类别&#xff…...

LLM - 第2版 ChatGLM2-6B (General Language Model) 的工程配置

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://blog.csdn.net/caroline_wendy/article/details/131445696 ChatGLM2-6B 是开源中英双语对话模型 ChatGLM-6B 的第二代版本&#xff0c;在保留了初代模型对话流畅、部署门槛较低等众多优…...

从0开始,手写MySQL事务

说在前面&#xff1a;从0开始&#xff0c;手写MySQL的学习价值 尼恩曾经指导过的一个7年经验小伙&#xff0c;凭借精通Mysql, 搞定月薪40K。 从0开始&#xff0c;手写一个MySQL的学习价值在于&#xff1a; 可以深入地理解MySQL的内部机制和原理&#xff0c;Mysql可谓是面试的…...

React中useState的setState方法请求了好多次

1、问题描述 最近在写react的时候碰到了一个很奇怪的问题。 可以看到那个getXXX()的方法一直不断的被调用&#xff0c;网页一直请求&#xff0c;根本停不下来了。 2、产生原因 要弄明白这个原因&#xff0c;首先要先了解一下react生命周期。 react是组件式的编程&#xff0c;一…...

【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元时&#xff0c;帐号被禁用&#xff0c;需追加网费。 二、在计算中心机房上机的用户&#xff0c;登录时请选择新建帐号时给您指定的NT域&…...

[SpringBoot]Spring Security框架

目录 关于Spring Security框架 Spring Security框架的依赖项 Spring Security框架的典型特征 关于Spring Security的配置 关于默认的登录页 关于请求的授权访问&#xff08;访问控制&#xff09; 使用自定义的账号登录 使用数据库中的账号登录 关于密码编码器 使用BCry…...

Unity 之 抖音小游戏本地数据最新存储方法分享

Unity 之 抖音小游戏本地数据最新存储方法分享 一、抖音小游戏文件存储系统背景二、文件存储系统的使用方法2.1 初始化2.1 创建目录2.3 存储数据2.4 删除目录/文件2.5 其他相关操作 三&#xff0c;小结 抖音小游戏是一种基于抖音平台开发的小型游戏&#xff0c;与传统的 APP 不…...

逍遥自在学C语言 | 函数初级到高级解析

前言 函数是C语言中的基本构建块之一&#xff0c;它允许我们将代码组织成可重用、模块化的单元。 本文将逐步介绍C语言函数的基础概念、参数传递、返回值、递归以及内联函数和匿名函数。 一、人物简介 第一位闪亮登场&#xff0c;有请今后会一直教我们C语言的老师 —— 自在…...

Elastic 推出 Elastic AI 助手

作者&#xff1a;Mike Nichols Elastic 推出了 Elastic AI Assistant&#xff0c;这是一款由 ESRE 提供支持的开放式、生成式 AI 助手&#xff0c;旨在使网络安全民主化并支持各种技能水平的用户。 最近发布的 Elasticsearch Relevance Engine™ (ESRE™) 提供了用于创建高度相…...

【数据库】MySQL安装(最新图文保姆级别超详细版本介绍)

1.总共两部分&#xff08;第二部可省略&#xff09; 安装mysql体验mysql环境变量配置 1.1安装mysql 1.输入官网地址https://www.mysql.com/ 下载完成后&#xff0c;我们双击打开我们的下载文件 打开后的界面&#xff0c;如图所示 我们选择custom&#xff0c;点击nex…...

前端使用pdf-lib库实现pdf合并,window.open预览合并后的pdf

最近出差开了好多发票&#xff0c;写了一个pdf合并网站&#xff0c;用于把多张发票pdf合并成一张&#xff0c;方便打印 使用pdf-lib这个库实现的pdf合并功能&#xff0c;预览使用的是浏览器自身查看pdf功能 源码 网页地址 https://zqy233.github.io/PDF-merge/ <!DOCTYPE h…...

计算机网络相关知识点总结(二)

比特bit是计算机中数据量的最小单位,可简记为b。字节Byte也是计算机中数据量的单位,可简记为B,1B8bit。常用的数据量单位还有kB、MB、GB、TB等,其中k、M、G、T的数值分别为 2 10 2^{10} 210, 2 20 2^{20} 220, 2 30 2^{30} 230, 2 40 2^{40} 240。 K, M, G, T 分别对应以下…...

Redmine与Gitlab整合(实战版)

网上查了很多文章&#xff0c;总结一下。 安装过程略。可参考&#xff1a;(84条消息) Redmine与Gitlab功能集成_redmine gitlab_羽之大公公的博客-CSDN博客 配置集成的方法&#xff0c;参考&#xff1a; Redmine与GitLab集成 (ngui.cc) 修改ssh-key密码的方法&#xff0c;参…...

(3)深度学习学习笔记-简单线性模型

文章目录 一、线性模型二、实例1.pytorch求导功能2.简单线性模型&#xff08;人工数据集&#xff09; 来源 一、线性模型 一个简单模型&#xff1a;假设一个房子的价格由卧室、卫生间、居住面积决定&#xff0c;用x1&#xff0c;x2&#xff0c;x3表示。 那么房价y就可以认为yw…...

pytorch3d 安装报错 RuntimeError: Not compiled with GPU support pytorch3d

安装环境 NVIDIA GeForce RTX 3090 cuda 11.3 python 3.8.5 torch 1.11.0 torchvision 0.12.0 环境安装命令 conda install pytorch1.11.0 torchvision0.12.0 torchaudio0.11.0 cudatoolkit11.3 -c pytorch安装pytorch3d参考官网链接 https://github.com/facebookresearch/p…...

spring工程的启动流程?bean的生命周期?提供哪些扩展点?管理事务?解决循环依赖问题的?事务传播行为有哪些?

1.Spring工程的启动流程&#xff1a; Spring工程的启动流程主要包括以下几个步骤&#xff1a; 加载配置文件&#xff1a;Spring会读取配置文件&#xff08;如XML配置文件或注解配置&#xff09;来获取应用程序的配置信息。实例化并初始化IoC容器&#xff1a;Spring会创建并初…...

使用 Zabbix 监控 RocketMQ列举监控项和触发器

在使用 Zabbix 监控 RocketMQ 的过程中&#xff0c;以下是一些可能的监控项和触发器&#xff1a; 监控项 集群总体健康状况生产者和消费者的连接数量Broker 的状态消息的生产和消费速度队列深度&#xff08;即队列中的消息数量&#xff09;磁盘空间使用内存使用CPU使用网络流…...

uniApp:路由与页面跳转及传参

方式一&#xff1a;声明式导航 声明式导航&#xff0c;通过组件进行跳转。官方文档&#xff1a;详情 使用 navigator 组件进行页面跳转。 属性类型默认值说明urlString应用内的跳转链接&#xff0c;值为相对路径或绝对路径&#xff0c;如&#xff1a;“…/first/first”&#x…...