JavaScript实现扁平数组与树结构的相互转换

扁平数组转为树结构

题目描述:

给定以下数据格式的扁平数组:

const flatArray = [{ id: 1, parentId: null, name: 'root1' },{ id: 2, parentId: 1, name: 'child1' },{ id: 3, parentId: 1, name: 'child2' },{ id: 4, parentId: 2, name: 'grandchild1' },{ id: 5, parentId: 3, name: 'grandchild2' },
];

你需要将其转换为以下树状结构:

const tree = [{"id": 1,"parentId": null,"name": "root1","children": [{"id": 2,"parentId": 1,"name": "child1","children": [{"id": 4,"parentId": 2,"name": "grandchild1","children": []}]},{"id": 3,"parentId": 1,"name": "child2","children": [{"id": 5,"parentId": 3,"name": "grandchild2","children": []}]}]}
];

请编写一个名为 flatArrayToTree 的函数,接受上述类型的扁平数组作为参数,并返回相应的树状结构数组。

方案一:使用Map和递归

function flatArrayToTree(flatArray) {// 创建一个映射,方便通过id查找节点const map = new Map();flatArray.forEach(item => {map.set(item.id, { ...item, children: [] });});// 定义一个递归函数,用于构建每个节点的子树function buildTree(node) {flatArray.forEach(item => {if (item.parentId === node.id) {const childNode = map.get(item.id);// 递归构建子树,并添加到当前节点的children中node.children.push(buildTree(childNode)); }});return node;}// 过滤出根节点并递归构建整棵树return flatArray.filter(item => item.parentId === null).map(rootNode => buildTree(map.get(rootNode.id)));
}const tree = flatArrayToTree(flatArray);

方案一解释

首先,我们创建一个 Map 来存储每个节点及其子节点列表。
接着定义一个递归函数 buildTree 用于构建父子关系。遍历扁平数组时,对于每个节点,将其添加到 Map 中并初始化其 children 属性为空数组。对于有 parentId 的节点,将其添加到相应父节点的 children 数组中。
最后从 Map 中提取 parentIdnull的节点形成结果数组。

方案二:使用对象作为索引和循环

function flatArrayToTree(flatData) {const result = [];const map = {};// 先构建一个id映射表flatData.forEach(item => {map[item.id] = { ...item, children: [] };});// 然后根据parentId将子节点添加到父节点的children属性下flatData.forEach(item => {if (item.parentId !== null) {map[item.parentId].children.push(map[item.id]);} else {result.push(map[item.id]);}});return result;
}const tree = flatArrayToTree(flatArray);

方案二解释

首先遍历扁平数组,创建一个键值对形式的哈希表,键是每个元素的 id,值是该元素本身。这样我们可以快速通过 id 找到对应的节点。
再次遍历扁平数组,对于每个元素,检查其 parentId 是否存在于哈希表中。如果存在,说明找到了其父节点,将当前元素添加到其父节点的 children 数组中。若不存在 parentId(即为根节点),则直接添加到结果数组中。
最终得到的结果数组就是所求的树形结构。

最深层级

在构建树结构的时候,如果需要记录最深层级,应该怎么做呢?下面是可以记录最深层级的方案:

function flatArrayToTree(flatData) {let maxDepth = 0;const result = [];const map = {};// 先构建一个id映射表flatData.forEach(item => {map[item.id] = { ...item, children: [], depth: 0 };});// 然后根据parentId将子节点添加到父节点的children属性下,并计算深度flatData.forEach(item => {if (item.parentId !== null) {const parent = map[item.parentId];parent.children.push(map[item.id]);// 更新当前节点及其父节点的深度let currentDepth = parent.depth + 1;map[item.id].depth = currentDepth;// 更新最大深度maxDepth = Math.max(maxDepth, currentDepth);} else {result.push(map[item.id]);}});return { tree: result, maxDepth };
}const { tree, maxDepth } = flatArrayToTree(flatArray);
console.log('Tree:', tree);
console.log('Max Depth:', maxDepth);

增加 maxDepth 变量记录最大深度,在每次将子节点添加到父节点的 children 属性下时,记录层级,计算深度。

树结构转扁平数组

以上是扁平数组转为树结构的情况,下面来看针对已有的树形结构,将其转换回扁平数组的情况。

实现

function treeToArray(treeNodes) {let result = [];//递归函数 traverse,用于处理单个节点function traverse(node) {const newNode = { ...node };delete newNode.children;// 将没有子节点的新节点添加到结果数组中result.push(newNode);// 如果当前节点包含 children 属性(即有子节点)if (node.children) {node.children.forEach(traverse);}}treeNodes.forEach(traverse);return result;
}const flatArray = treeToArray(tree);

解释

首先定义了一个 treeToArray 函数,该函数内部定义了一个名为 traverse 的递归函数,用于遍历树形结构的每一个节点并将节点添加到扁平数组中。
然后遍历输入的树形结构,对每个节点调用 traverse 函数。在 traverse 函数内部,如果当前节点有子节点,则对其每个子节点进行同样的遍历操作。
最后返回扁平数组。

总结

在解决扁平数组与树结构之间的转换问题时,关键在于识别父子关系并通过建立索引或映射结构进行层次遍历,以实现数据的转换。
在实际业务中,扁平数组与树结构的转化,常见在目录树组件,级联选择组件等情况。

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

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

相关文章

《LeetCode力扣练习》代码随想录——二叉树(合并二叉树---Java)

《LeetCode力扣练习》代码随想录——二叉树(合并二叉树—Java) 刷题思路来源于 代码随想录 617. 合并二叉树 二叉树-前序遍历 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode…

【THM】Exploit Vulnerabilities(利用漏洞)-

介绍 在这个房间里,我们将讨论一些识别漏洞的方法,并结合我们的研究技能来了解这些漏洞是如何被滥用的。 此外,您还会发现一些公开可用的资源,这些资源是您在执行漏洞研究和利用时的技能和工具的重要补充。然后,您将在房间的最后将所有这些应用到实际挑战中。 自动化与…

HTML5.Canvas简介

1. Canvas.getContext getContext(“2d”)是Canvas元素的方法,用于获取一个用于绘制2D图形的绘图上下文对象。在给定的代码中,首先通过getElementById方法获取id为"myCanvas"的Canvas元素,然后使用getContext(“2d”)方法获取该Ca…

STM3定时器输入捕获、超声波测距

1、超声波测距模块介绍 1、HC-SR04共四个引脚:VCC、GND、Trig、Echo,如下图 2、使用 1、通过gpio口向Trig引脚发送一个脉冲信号。 2、HC-SR04接收到脉冲信号后,就会向外发送一段超声波,模块会将echo拉高。 …

pandas 数据排序.sort_index()和.sort_values()使用教程

import pandas as pd df pd.DataFrame(……) 说明:以下“df”为DataFrame对象。 1. df. sort_values() 作用:既可以根据列数据,也可根据行数据排序。 注意:必须指定by参数,即必须指定哪几行或哪几列;无法…

rpm、yum和编译安装软件

一、rpm 1.rpm包管理工具 建立统一的数据库文件(一张对应表将信息写入) 详细记录软件包安装、卸载等变化信息,自动分析软件包依赖关系 2.rpm一般命令格式 bash-4.1.2-15.el6_4.x86_64.rpm bash(shell软件名称) …

STM32CubeIDE基础学习-定时器PWM实验

STM32CubeIDE基础学习-定时器PWM实验 文章目录 STM32CubeIDE基础学习-定时器PWM实验前言第1章 硬件介绍第2章 工程配置2.1 基础工程配置部分2.2 生成工程代码部分 第3章 代码编写3.1 查看PWM波3.2 设置单个比较值3.3 呼吸灯 第4章 实验现象总结 前言 在平时单片机开发时&#…

JQuery(一)---【JQuery简介、安装、初步使用、各种事件】

零.前言 在学习JQuery前,您需要具备以下知识: HTML相关知识(DOM)CSS相关知识JavaScript相关知识 一.JQuery 1.1JQuery简介 JQuery是一个JavaScript的“函数库”,不是JavaScript的一个框架,与“VUE、REACT”有本质区别&#x…

字符串匹配问题(strs)(栈)

字符串匹配问题(strs) 【题目描述】 字符串中只含有括号 (),[],<>,{},判断输入的字符串中括号是否匹配。如果括号有互相包含的形式&#xff0c;从内到外必须是<>,(),[],{}&#xff0c;例如。输入: [()] 输出:YES&#xff0c;而输入([])&#xff0c;([)]都应该输出…

IPSEC VPN双机热备份的配置讲解一

IPSEC VPN双机热备份的配置讲解一 VPN 是一种专用网络&#xff0c;可使用公共网络连接两个或两个以上的远程站点。VPN 可使用通过公共网络路由&#xff08;以隧道方式发送&#xff09;的虚拟连接&#xff0c;而非网络之间的专用连接。IPsec VPN 是一项协议&#xff0c;由建立 …

HTML如何设置字体样式?

HTML如何设置字体样式&#xff1f; 我们开发一个页面时&#xff0c;会经常涉及到文字部分。HTML 默认的字体样式为宋体&#xff0c;12px。如果我们不想设置字体为宋体的话&#xff0c;需要为它更改样式。HTML 字体样式的更改需要用到 CSS。 CSS 常用的字体属性有五种&#xf…

DHCP-PXE

Dynamic Host Configuration Protocol 动态主机配置协议 1.Selinux 调试为Permission 防火墙配置 搭建DHCP的主机必须有一个静态地址&#xff0c;提前配置好 安装DHCP软件 服务名为dhcpd DHCP地址分配四次会话&#xff0c; DISCOVERY发现 OFFER 提供 REQUEST 回应 A…

【C++】每日一题 380 O(1)时间插入,删除和获取随机元素

实现RandomizedSet 类&#xff1a; RandomizedSet() 初始化 RandomizedSet 对象 bool insert(int val) 当元素 val 不存在时&#xff0c;向集合中插入该项&#xff0c;并返回 true &#xff1b;否则&#xff0c;返回 false 。 bool remove(int val) 当元素 val 存在时&#xf…

代码随想录算法训练营第42天| 背包问题、416. 分割等和子集

01 背包 题目描述&#xff1a;有n件物品和一个最多能背重量为w 的背包。第i件物品的重量是weight[i]&#xff0c;得到的价值是value[i] 。每件物品只能用一次&#xff0c;求解将哪些物品装入背包里物品价值总和最大。 二维dp数组01背包&#xff1a; 确定dp数组以及下标的含义 …

实景三维技术也是一种新质生产力

实景三维技术作为一种新兴的技术手段&#xff0c;正在逐渐被认为是一种新质生产力。它通过高精度的数据采集、处理和可视化&#xff0c;为多个行业领域提供了全新的工作方式和解决方案&#xff0c;从而推动了生产力的发展和创新。以下是实景三维技术作为新质生产力在不同方面的…

2024年华为OD机试真题-最长的指定瑕疵度的元音子串-Java-OD统一考试(C卷)

题目描述: 开头和结尾都是元音字母(aeiouAEIOU)的字符串为 元音字符串 ,其中混杂的非元音字母数量为其 瑕疵度 。比如: “a” 、 “aa”是元音字符串,其瑕疵度都为0 “aiur”不是元音字符串(结尾不是元音字符) “abira”是元音字符串,其瑕疵…

Mac 配置 Aria2

文章目录 1. Aria2 安装1.1 安装 brew1.2 安装 Aria2 2. 配置 Aria22.1 创建配置文件 aria2.conf 和空对话文件 aria2.session2.2 编辑配置文件 aria2.conf 3. 开机启动设置3.1 创建用户启动文件3.2 管理自启动项 4. 配置 BT tracker 自动更新4.1 XIU2/TrackersListCollection …

通义灵码-ai编码

https://developer.aliyun.com/topic/lingma/activities/202403?taskCode14508&recordIdb1ef3ba27250a5818b1b6ffe418af658#/?utm_contentm_fission_1 「通义灵码 体验 AI 编码&#xff0c;开 AI 盲盒」

Python笔记|列表推导式

用列表推导式创建列表的方式更简洁。常见的用法为&#xff0c;对序列或可迭代对象中的每个元素应用某种操作&#xff0c;用生成的结果创建新的列表&#xff1b;或用满足特定条件的元素创建子序列。 例如&#xff0c;创建平方值的列表&#xff1a; >>> squares [] &…

【Kafka】Kafka安装、配置、使用

【Kafka】安装Kafka 1. 安装Kafka2. Kafka使用2.0 集群分发脚本xsync(重要)2.0.1 scp命令2.0.2 rsync远程同步工具2.0.3 写一个集群分发脚本xsync (Shell 脚本) 2.1 Zookeeper安装2.2 对Kafka进行分发2.2.1 执行同步脚本2.2.2 三台云主机配置Kafka环境变量 1. 安装Kafka Kafka…