JS实现树形结构、一维数组以及map之间的转换

news2024/12/22 20:37:54
const treeData=[
{id:1,
name:'中国',
children:[
{
    id:11,
    name:'河南省',
    children:[
        {
            id:111,
            name:'南阳市',
            children:[
                {
                    id:1111,
                    name:'淅川县',
                    children:null
                }
            ]
        },
        {
            id:112,
            name:'郑州市',
            children:[
            {
                id:1121,
                name:'中牟县',
                children:null
            }]
        }
    ]
},
{
    id:22,
    name:'广东省',
    children:[
        {
            id:221,
            name:'深圳市',
            children:[
                {
                    id:2211,
                    name:'宝安区',
                    children:null
                },{
                    id:2212,
                    name:'福田区',
                    children:null
                }
            ]
        },
        {
            id:222,
            name:'广州市',
            children:[{
                id:2221,
                name:'天河区',
                children:null
            },{
                id:2222,
                name:'南沙区',
                children:null
            }]
        }
    ]
}]}
]
const listData1=[
{id:1,name:'中国'},
{id:11,name:'河南省',pid:1},
{id:111,name:'南阳市',pid:11},
{id:1111,name:'淅川县',pid:111},
{id:112,name:'郑州市',pid:11},
{id:1121,name:'中牟县',pid:112},
{id:12,name:'广东省',pid:1},
{id:121,name:'深圳市',pid:12},
{id:1211,name:'宝安区',pid:121},
{id:1212,name:'福田区',pid:121},
{id:122,name:'广州市',pid:12},
{id:1221,name:'天河区',pid:122},
{id:1222,name:'南沙区',pid:122},
]

1、一维数组转树形结构

1.1、递归

//一维数组转树形结构
function listToTree(list){
    const tree=[]
    for(const node of list){
        //如果是父节点
        if(!node.pid){
            let p={...node}
            p.children=getChildren(p.id,list)
            tree.push(p)
        }
    }
    return tree
}
function getChildren(id,list){
    const children=[]
    //遍历数组的每一个元素,如果找到元素的父元素节点等于当前节点,则向children中添加该元素
    for(const node of list){
        if(node.pid===id){
            children.push(node)
        }
    }

    //遍历每一个孩子节点,递归寻找孩子的孩子节点,如果存在children,则向node的children中添加
    for(const node of children){
        const children=getChildren(node.id,list)
        if(children.length){
            node.children=children
        }
    }
    return children
}

demo:

console.log(listToTree(listData))

打印后的结果和treeData一致。

1.2、双层循环

// 双层循环:找出每一个元素的父节点,向每一个父节点增加children属性
function listToTree2(list){
   list.forEach(child=>{
       const pid=child.pid
       //遍历子节点,然后遍历每一个list节点,从中找出父节点,向父节点增加孩子元素
       if(pid){
           list.forEach(parent=>{
               if(parent.id===pid){
                    //如果找到的父节点还没有孩子,会默认为空数组,否则为原来的子节点数组                    
                   parent.children=parent.children||[]
                   parent.children.push(child)
               }
           })
       }
   })
}

结果同1.1

1.3、使用map

//Map
function listToListMap(list){
    const [map,treeData]=[{},[]]
    //将map转为以id为key,索引为value的对象
    //将数组中每个元素的children初始化为空数组
    for(let i=0;i<list.length;i++){
        map[list[i].id]=i;
        list[i].children=[]
    }
    console.log(map)
    for(let i=0;i<list.length;i++){
        const node=list[i]
        //如果是子元素并且子元素的父节点存在在list中,则找到父元素并向父元素的children中加入子元素
        if(node.pid&&list[map[node.pid]]){
            list[map[node.pid]].children.push(node)
        }else{
            //说明不是子元素,是父元素直接放入treeData中
            treeData.push(node)
        }
    }
    return treeData
}

2、tree转list

树形结构转数组涉及到树的遍历,树的遍历分为深度遍历(前中后序)和广度遍历。

2.1、广度遍历

const treeData3=[
{id:1,
name:'中国',
children:[
{
    id:11,
    name:'河南省',
    children:[
        {
            id:111,
            name:'南阳市',
            pid:11,
            children:[
                {
                    id:1111,
                    name:'淅川县',
                    children:null,
                    pid:111,

                }
            ]
        },
        {
            id:112,
            name:'郑州市',
            pid:11,
            children:[
            {
                id:1121,
                pid:112,
                name:'中牟县',
                children:null
            }]
        }
    ]
},
{
    id:22,
    name:'广东省',
    children:[
        {
            id:221,
            pid:22,
            name:'深圳市',
            children:[
                {
                    id:2211,
                    pid:221,
                    name:'宝安区',
                    children:null
                },{
                    id:2212,
                    pid:221,
                    name:'福田区',
                    children:null
                }
            ]
        },
        {
            id:222,
            pid:22,
            name:'广州市',
            children:[{
                id:2221,
                pid:222,
                name:'天河区',
                children:null
            },{
                id:2222,
                pid:222,
                name:'南沙区',
                children:null
            }]
        }
    ]
}]}
]
//广度遍历(一层一层遍历)
function treeToList(treeData){
    const list=[]
    const queue=[...treeData]
    while(queue.length){
        //取队头元素         
        const node=queue.shift()
        const children=node.children
        //将队头元素的孩子依次放入队列中便于后序遍历
        if(children){
            queue.push(...children)
        }
        //放入元素节点
        list.push(node)
    }
    return list
}
console.log(treeToList(treeData3))

打印结果同1中的listData

2.2、深度遍历

//深度遍历(采用栈)
function treeToList2(tree){
    const list=[]
    const stack=[...tree]
    while(stack.length){
        const node=stack.pop()
        //如果出栈的节点有孩子元素,那么将出栈元素的所有孩子元素都放入栈中,便于后续遍历.
        const children=node.children
        if(children){
            stack.push(...children)
        }
        list.push(node)
    }
    return list
}

3、list转Map(map是以父节点id为key,所有子节点作为数组为value的数据结构)

const listData4=[
{id:1,name:'中国'},//0
{id:11,name:'河南省',pid:1},//1
{id:111,name:'南阳市',pid:11},//2
{id:1111,name:'淅川县',pid:111},//3
{id:112,name:'郑州市',pid:11},//4
{id:1121,name:'中牟县',pid:112},//5
{id:12,name:'广东省',pid:1},//6
{id:121,name:'深圳市',pid:12},//7
{id:1211,name:'宝安区',pid:121},//8
{id:1212,name:'福田区',pid:121},//9
{id:122,name:'广州市',pid:12},//10
{id:1221,name:'天河区',pid:122},//11
{id:1222,name:'南沙区',pid:122},//12
]
// 将列表数据转为以父节点id为key,子节点为value的map
function listToMap(list){
    const map={}
    list.forEach(item=>{
        for(let i=0;i<list.length;i++){
            //如果外层循环元素的id等于内层循环元素的pid,说明内层元素是外层元素的子元素,则向map的value中添加该内层元素.
            if(list[i].pid===item.id){
                map[item.id]=map[item.id]||[]
                map[item.id].push(list[i])
            }
        }
    })
    return map
}
console.log(listToMap(listData4))

 

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

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

相关文章

【【verilog典型电路设计之流水线结构】】

verilog典型电路设计之流水线结构 下图是一个4位的乘法器结构&#xff0c;用verilog HDL 设计一个两级流水线加法器树4位乘法器 对于流水线结构 其实需要做的是在每级之间增加一个暂存的数据用来存储 我们得到的东西 我们一般来说会通过在每一级之间插入D触发器来保证数据的联…

创建Azure资源锁

锁的介绍 在Azure中&#xff0c;资源锁是一种用于保护订阅、资源组或者单个资源的机制。它可以防止对受锁定的资源进行删除或修改操作&#xff0c;帮助确保资源的连续可用性和安全性。 Azure中的资源锁可以分为两种类型&#xff1a; 删除锁&#xff08;CanNotDelete&#xf…

实现Excel数据复制分录信息粘贴到金蝶单据体中

>>>适合KIS云专业版V16.0|KIS云旗舰版V7.0|K/3 WISE 14.0等版本<<< 实现Excel数据复制分录信息粘贴到金蝶单据体分录中,在采购订单|采购入库单|销售订单|销售出库单等类型单据中,以少量的必要字段在excel表格中按模板填列好,很方便快捷地复制到金蝶单据表体…

三分钟完美解决你的C盘内存过大爆红

一、清理回收站 二、清理桌面 建议一 不要在桌面放太多图标或者文件会占用过多的内存,可以放到其他盘建议二、 将位置移动到别的盘 三、手动删除下载文件与缓存文件 日常使用中会通过Windows下载各种文件资料到电脑中&#xff0c;它默认也是直接下载在C盘中的。如果我们在以…

ssm+JSP的乡镇自来水收费系统源码和论文PPT

ssmJSP的乡镇自来水收费系统源码和论文PPT014 开发工具&#xff1a;idea 数据库mysql5.7(mysql5.7最佳) 数据库链接工具&#xff1a;navcat,小海豚等 开发技术&#xff1a;java ssm tomcat8.5 一、课题背景与意义 随着我国经济建设迅速发展&#xff0c;乡镇规模日益扩大&am…

RK3568 HDMI接口

一.简介 HDMI接口&#xff0c;中文全称为高清多媒体接口。是一种全数字化视频以及声音发送接口&#xff0c;能够发送没有压缩的音频以及视频信号。HDMI接口可以使用在机顶盒、DVD播放机等设备商。除此之外&#xff0c;HDMI接口还可以同时发送音频以及视频信号&#xff0c;简化…

22款美规奔驰GLS450更换AMG GLS63原厂刹车卡钳系统,刹车效果强悍无比

AMG出品的大六活塞卡钳及大直径开孔刹车碟&#xff0c;所组成的制动套件。这套AMG出品的卡钳为制动生产名厂BREMBO为其代工&#xff0c;刹车碟是高锻钢锻造&#xff0c;耐高温耐用性能较高且打孔设计。

什么是事务,并发带来的事务问题以及事务隔离级别(图文详解)

一、什么是事务&#xff1f; 简单说就是逻辑上的一组操作&#xff0c;要么都执行&#xff0c;要么都不执行。 举个例子&#xff0c;假如小明要给小红转账100元&#xff0c;这个转账会涉及到两个关键操作&#xff1a;①将小明的余额减少100元。 ②将小红的余额增加100元 。但…

【左神算法刷题班】第18节:汉诺塔问题、岛屿问题、最大路径和问题

第18节 题目1&#xff1a;汉诺塔问题&#xff08;变体&#xff09; 体系学习班18节有讲暴力递归的汉诺塔原题。 给定一个数组arr&#xff0c;长度为N&#xff0c;arr中的值只有1&#xff0c;2&#xff0c;3三种 arr[i] 1&#xff0c;代表汉诺塔问题中&#xff0c;从上往下第…

Azure添加网络接口

添加网络接口的意义 在 Azure 上&#xff0c;为虚拟机添加网络接口的意义包括以下几个方面&#xff1a; 扩展网络带宽&#xff1a;通过添加多个网络接口&#xff0c;可以增加虚拟机的网络带宽&#xff0c;提高网络传输速度和数据吞吐量。实现网络隔离&#xff1a;每个网络接口…

网络安全体系架构介绍

网络安全体系是一项复杂的系统工程&#xff0c;需要把安全组织体系、安全技术体系和安全管理体系等手段进行有机融合&#xff0c;构建一体化的整体安全屏障。针对网络安全防护&#xff0c;美国曾提出多个网络安全体系模型和架构&#xff0c;其中比较经典的包括PDRR模型、P2DR模…

2021年06月 C/C++(二级)真题解析#中国电子学会#全国青少年软件编程等级考试

第1题&#xff1a;数字放大 给定一个整数序列以及放大倍数x&#xff0c;将序列中每个整数放大x倍后输出。 时间限制&#xff1a;1000 内存限制&#xff1a;65536 输入 包含三行&#xff1a; 第一行为N&#xff0c;表示整数序列的长度(N ≤ 100); 第二行为N个整数(不超过整型范围…

一个脚本 专治杂乱

背景 之前不是自己手动搞了一个COS嘛&#xff0c;直接复制粘贴图片&#xff0c;上传到后端的服务器&#xff0c;返回一个可访问的地址。我在哔哩哔哩上也分享过这样的一期视频。 今天偶尔上服务器一看&#xff0c;我靠&#xff0c;我的文件真的乱&#xff01; 这还得了了&…

【C++精华铺】7.C++内存管理

目录 1. C语言动态内存管理 2. C内存管理方式 2.1 new/delete和new T[]/delete[] 2.1.1 操作内置类型 2.1.2 操作自定义类型 2.2 new/delete和new T[]/delete[]的原理 2.2.1 原理 2.2.2 operator new和operator delete 2.2.3 new T[]的特殊处理&#xff08;可以…

Altium DXP原理图转换成Orcad Capture

买了个开发板&#xff0c;原图是Altium DXP的&#xff0c;但是个人熟悉的Orcad&#xff0c;PCB无所谓了&#xff0c;反正都要重画&#xff0c;但是原理图是件大工程&#xff0c;重画还可能出问题&#xff0c;所以想着把DXP转成Capture格式&#xff0c;查阅了相关文档&#xff0…

【Linux命令详解 | ps命令】 ps命令用于显示当前系统中运行的进程列表,帮助监控系统状态。

文章标题 简介一&#xff0c;参数列表二&#xff0c;使用介绍1. 基本用法2. 显示所有进程3. 显示进程详细信息4. 根据CPU使用率排序5. 查找特定进程6. 显示特定用户的进程7. 显示进程内存占用8. 查看进程树9. 实时监控进程10. 查看特定进程的详细信息11. 查看特定用户的进程统计…

RTT(RT-Thread)串口设备(RTT保姆级教程)

目录 UART串口设备 串口概述 访问串口设备接口 数据发送方法 数据接收方法 串口设备使用流程 串口中断接受实例 串口配置及串口发送 串口中断接收 DMA接收 UART串口设备 串口概述 本章主要介绍串口设备在RT-Thread操作系统中应用层如何使用。关于串口设备的使用&am…

解析TCP/IP协议的分层模型

了解ISO模型&#xff1a;构建通信的蓝图 为了促进网络应用的普及&#xff0c;国际标准化组织&#xff08;ISO&#xff09;引入了开放式系统互联&#xff08;Open System Interconnect&#xff0c;OSI&#xff09;模型。这个模型包括了七个层次&#xff0c;从底层的物理连接到顶…

Spring AOP实践:如何通过aop记录日志?

目录 一、依赖 二、自定义注解 三、切面 一、依赖 以SpringBoot工程为例&#xff0c;导入aop的依赖。 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId> </dependency> 二…

GCviewer分析java垃圾回收的情况

一&#xff0c;下载并打包 1.在github上下载gcviewer,并解压。 2. 运行maven命令打包。mvn clean package -DskipTests 二&#xff0c;启动GCViewer 进入target目录&#xff0c;运行 java -jar gcviewer-1.37-SNAPSHOT.jar 运行后&#xff0c;会出来界面 三&#xff0c;加参…