JavaScript前端面试扁平数据转tree与tree数据扁平化

目录
  • 一、写在前面
  • 二、正文部分
    • 2.1 扁平数据转为 tree 数据
    • 2.2 tree 数据转为扁平数据
    • 2.3 完整测试 demo
  • 三、写在后面

一、写在前面

有时我们拿到的数据的数据结构可能不是理想的,那么此时就要求前端程序员,具有改造数据的能力。例如拿到扁平的数据, 但我们要应用在 tree 树形组件或 Cascader 级联选择器组件中,这样的组件要求数据结构是非扁平的的具有层级递进关系的 tree 结构。

总之就是说,提供数据的接口给到的数据,未必符合要求,而当我们又无法令他人为为我们改变时,需求和要求就来到了前端程序员这里, 所以得具备这样的数据处理能力。

下面是将举两个数据改造的例子:

  • 一是扁平化,具有层级递进关系的 tree 数据,转换为扁平结构的的 flat 数据
  • 二是反扁平化,扁平结构的 flat 数据,转换为具有层级递进关系的 tree 数据

二、正文部分

2.1 扁平数据转为 tree 数据

扁平化函数

  /**
   * 扁平化:将具有层级递进关系结构的 tree 数据扁平化
   *
   * @param treeList 有层级递进关系结构的 tree 数据
   * @param flatList 用于接收扁平化结果的变量
   * @returns {*} 返回扁平化结果
   */
  function treeToFlat (treeList, flatList) {
    // flatList.length > 9999 是考虑底线保护原则,出于极限保护的目的设置的,可不设或按需设置。
    if (flatList.length > 9999) {
      return
    }
    treeList.map(e => {
      flatList.push(e)
      // 递归:有条件的自己调用自己,条件是 e.children.length 为真
      if (e.children && e.children.length) {
        treeToFlat(e.children, flatList)
      }
    })
    // console.log('扁平化后:', flatList)
    return flatList
  }

2.2 tree 数据转为扁平数据

反扁平化函数

  /**
   * 反扁平化:将扁平结构的 flat 数据转换为具有层级递进关系结构的 tree 数据
   *
   * @param flatList 扁平结构的数据
   * @param treeList 用于接收反扁平化结果的变量
   * @returns {*} 返回反扁平化结果
   */
  function flatToTree (flatList, treeList) {
    flatList.map(e => {
      // 以 e.pid===null,作为判断是不是根节点的依据,或者直接写死根节点(如果确定的话),
      // 具体以什么作为判断根节点的依据,得看数据的设计规则,通常是判断层级或是否代表根节点的标记
      if (e.pid === null) {
        // 避免出现重复数据
        const index = treeList.findIndex(sub => sub.id === e.id)
        if (index === -1) {
          treeList.push(e)
        }
      }
      flatList.map(e2 => {
        if (e2.pid === e.id) {
          // 避免出现重复数据
          const index = e.children.findIndex(sub => sub.id === e2.id)
          if (index === -1) {
            e.children.push(e2)
          }
        }
      })
    })

2.3 完整测试 demo

demo 测试结果截图如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title>扁平数据转tree与tree数据扁平化 Demo</title>
</head>
<body>
<h1>扁平数据转tree与tree数据扁平化</h1>
<script>
  window.onload = function () {
    test()
  }
  function test () {
    let flatList = [],
      treeList = [
        {
          id: 1,
          pid: null,
          label: '第一层',
          value: '1',
          children: [
            {
              id: 2,
              pid: 1,
              label: '第二层1',
              value: '2.1',
              children: []
            },
            {
              id: 3,
              pid: 1,
              label: '第二层2',
              value: '2.2',
              children: []
            },
            {
              id: 4,
              pid: 1,
              label: '第二层3',
              value: '2.3',
              children: [
                {
                  id: 5,
                  pid: 4,
                  label: '第三层1',
                  value: '3.1',
                  children: []
                },
                {
                  id: 6,
                  pid: 4,
                  label: '第三层2',
                  value: '3.2',
                  children: []
                },
              ]
            },
          ]
        }
      ]
    console.log('原始 tree 数据:', JSON.parse(JSON.stringify(treeList)))
    // 扁平化
    console.log('tree =>flat,扁平化后:', treeToFlat(JSON.parse(JSON.stringify(treeList)), flatList))
    // 反扁平化,SON.parse(JSON.stringify()) 为了实现深拷贝
    console.log('flat =>tree,反扁平化后:', flatToTree(JSON.parse(JSON.stringify(flatList)), treeList))
  }
  /**
   * 扁平化:将具有层级递进关系结构的 tree 数据扁平化
   *
   * @param treeList 有层级递进关系结构的 tree 数据
   * @param flatList 用于接收扁平化结果的变量
   * @returns {*} 返回扁平化结果
   */
  function treeToFlat (treeList, flatList) {
    // flatList.length > 9999 是考虑底线保护原则,出于极限保护的目的设置的,可不设或按需设置。
    if (flatList.length > 9999) {
      return
    }
    treeList.map(e => {
      flatList.push(e)
      // 递归:有条件的自己调用自己,条件是 e.children.length 为真
      if (e.children && e.children.length) {
        treeToFlat(e.children, flatList)
      }
    })
    // console.log('扁平化后:', flatList)
    return flatList
  }
  /**
   * 反扁平化:将扁平结构的 flat 数据转换为具有层级递进关系结构的 tree 数据
   *
   * @param flatList 扁平结构的数据
   * @param treeList 用于接收反扁平化结果的变量
   * @returns {*} 返回反扁平化结果
   */
  function flatToTree (flatList, treeList) {
    flatList.map(e => {
      // 以 e.pid===null,作为判断是不是根节点的依据,或者直接写死根节点(如果确定的话),
      // 具体以什么作为判断根节点的依据,得看数据的设计规则,通常是判断层级或是否代表根节点的标记
      if (e.pid === null) {
        // 避免出现重复数据
        const index = treeList.findIndex(sub => sub.id === e.id)
        if (index === -1) {
          treeList.push(e)
        }
      }
      flatList.map(e2 => {
        if (e2.pid === e.id) {
          // 避免出现重复数据
          const index = e.children.findIndex(sub => sub.id === e2.id)
          if (index === -1) {
            e.children.push(e2)
          }
        }
      })
    })
    // console.log('反扁平化后:', treeList)
    return treeList
  }
</script>
</body>
</html>

三、写在后面

这两个扁平化与反扁平化写法,感觉还有值得优化的方法,但暂时想不到。

此外,递归的应用也是值得注意的地方。

我理解的递归:有条件的自己调用自己

以上就是JavaScript前端面试扁平数据转tree与tree数据扁平化的详细内容,更多关于扁平数据转tree数据扁平化的资料请关注我们其它相关文章!

(0)

相关推荐

  • 高级前端面试手写扁平数据结构转Tree

    目录 前言 什么是好算法,什么是坏算法 时间复杂度 计算方法 空间复杂度 计算方法: 不考虑性能实现,递归遍历查找 不用递归,也能搞定 最优性能 小试牛刀 前言 招聘季节一般都在金三银四,或者金九银十.最近在这五六月份,陆陆续续面试了十几个高级前端.有一套考察算法的小题目.后台返回一个扁平的数据结构,转成树. 我们看下题目:打平的数据内容如下: let arr = [ {id: 1, name: '部门1', pid: 0}, {id: 2, name: '部门2', pid: 1}, {id:

  • js实现树形数据转成扁平数据的方法示例

    利用递归的方法循环树形数组,当遇到有children的对象再次调用递归函数循环children数组,每次循环的数据放入一个提前声明好的数组里,等所有递归函数执行完,这个数组即是想要得到的扁平数据数组. let res = [] const fn = (source)=>{ source.forEach(el=>{ res.push(el) el.children && el.children.length>0 ? fn(el.children) : ""

  • javascript将扁平的数据转为树形结构的高效率算法

    当我们需要将一个一维数组转换成一个多层结构的时候,最简单但是最慢的就是多个for循环嵌套,但是这样做有一些缺点,那就是效率太低.而且有多少层就需要嵌套几个for循环,不好用. 我实现了用O(n)级算法将 一个扁平的数组即一维数组代表的菜单结构转换成一个多层级的菜单结构. 一位数组中每一个元素必须要包含以下属性: 拥有一个唯一的id 拥有一个parent_id, 这个id指向它父级的id 其他则为每一个元素中的一些信息,我这里是菜单,就有菜单的名称和url信息. 注: 在层级结构中,第一层的par

  • js实现无限层级树形数据结构(创新算法)

    由于做项目的需要,把一个线性数组转成树形数组,在网上查了很多文章,觉得他们写的太复杂了,于是自己写了一个,在折腾了一下午终于把它写出来啦(激动.gif),用两个filter过滤器就搞定了,代码简洁明了,数据结构小白都能看懂. js代码:把扁平数据转成树形数据 function setTreeData(source){ let cloneData = JSON.parse(JSON.stringify(source)) // 对源数据深度克隆 return cloneData.filter(fat

  • JavaScript必看的10道面试题总结(推荐)

    1.this指向 1.谁调用指向谁 例: function foo(){ console.log("this",this); } new foo(); 2.全局指向window 例: function foo(){ console.log("this",this); } foo(); 3.构造函数的this指向构造函数实例 4.call/apply/bind 强制改变this指向 5.箭头函数的this始终指向父级上下文 2.事件模型:事件委托.代理?如何让事件先冒

  • JavaScript前端面试扁平数据转tree与tree数据扁平化

    目录 一.写在前面 二.正文部分 2.1 扁平数据转为 tree 数据 2.2 tree 数据转为扁平数据 2.3 完整测试 demo 三.写在后面 一.写在前面 有时我们拿到的数据的数据结构可能不是理想的,那么此时就要求前端程序员,具有改造数据的能力.例如拿到扁平的数据, 但我们要应用在 tree 树形组件或 Cascader 级联选择器组件中,这样的组件要求数据结构是非扁平的的具有层级递进关系的 tree 结构. 总之就是说,提供数据的接口给到的数据,未必符合要求,而当我们又无法令他人为为我

  • JavaScript前端面试组合函数

    经历过一些列的函数式编程思想的学习总结,一些重要的高阶函数的学习,以及前一段时间关于 RxJS 的学习. 我们再回看一次 —— 组合函数 compose 本瓜越来越觉得,[易读]的代码应该是将声明和调用分开来的.根据不同的流程,用函数组合的方式.也可以说它是管道.或者说是链式调用,将声明的函数组合起来,再等待时机进行调用. 如果没有组合函数 compose,函数连续调用将会是嵌套的: const multi10 = function(x) { return x * 10; } const toS

  • 前端面试JavaScript高频手写大全

    目录 1. 手写instanceof 2. 实现数组的map方法 3. reduce实现数组的map方法 4. 手写数组的reduce方法 5. 数组扁平化 5. 1 es6提供的新方法 flat(depth) 5.2 利用cancat 6. 函数柯里化 7. 浅拷贝和深拷贝的实现 7.1浅拷贝和深拷贝的区别 8. 手写call, apply, bind 8.1 手写call 8.2 手写apply(arguments[this, [参数1,参数2.....] ]) 8.3 手写bind 9.

  • javascript前端和后台进行数据交互方法示例

    在开发中遇到了在没有jQuery的情况下需要与后台进行部分数据的交互,查找了部分资料使用JavaScript实现了操作,记录一下. //获取XMLHttpRequest对象用于与后台交互数据 function getXHR(){ var xmlHttp; try { xmlHttp=new XMLHttpRequest();//新版本浏览器 }catch(e) { try{ xmlHttp=new ActiveXObject("Msxml2.XMLHTTP"); } catch(e)

  • JavaScript面试之如何实现数组拍平(扁平化)方法

    目录 1 什么叫数组拍平? 2 JS标准库中的数组拍平方法 3 实现一个flat方法 3.1 如何遍历一个数组 3.2 如何判断元素是否为数组 3.3 递归 3.4 初步实现flat方法 4 优化 4.1 指定展开深度 4.2 数组空位处理 4.2.1 for...of增加空位判断 4.2.2 forEach.map方法遍历 4.2.3 reduce方法 5 其他 5.1 栈 5.2 改进 总结 1 什么叫数组拍平? 概念很简单,意思是将一个"多维"数组降维,比如: // 原数组是一个

  • JS前端面试数组扁平化手写flat函数示例

    目录 前言 题目 实现扁平化的方法 封装 flatten 1. ES6 flat 2. toString 3. 使用正则替换 4. 循环递归 4.1 循环 + concat + push 4.2 增加参数控制扁平化深度 4.3 巧用 reduce 4.4 使用 Generator 函数 5. 使用堆栈 stack 避免递归 6.while 循环+ some方法 前言 由于上半年参加了校招的技术面试, 前前后后面了20多个人了, 每次面试都会让应聘者手写一下数组扁平化flat(),但是发现居然没有

  • JavaScript前端实用的工具函数封装

    目录 1.webpack里面配置自动注册组件 2.自定义指令图片懒加载 3.图片文件转base64格式(实现预览) 4.数组转为tree型结构(递归实现) 5.递归深拷贝 6.将数组里面的对象转换成我们需要的键值对 1.webpack里面配置自动注册组件 第一个参数是匹配路径,第二个是深度匹配,第三个是匹配规则 const requireComponent = require.context('./libary', true, /\.vue$/) export default { install

  • 自己动手写的javascript前端等待控件

    等待控件在网上搜有好多种,但是都很复杂,不一定用的顺手,再说我的项目是bootstrap的原因,又不敢轻易使用第三方控件,怕不兼容,于是自己动手写了个等待控件,其技术点包括动态加载CSS,javascript的命名空间,所以记录一下. 这个等待控件主要是:进行某个操作前,显示一个信息提示:"数据加载中,请稍候...",操作成功后,在回调函数中将提示消失,原理是这个等待控件完全由JS动态加进去,包括CSS,页面中并无预先设定. 那么这个CSS怎么动态加载呢?等待控件中,样式使用了clas

  • js前端面试之同步与异步问题详解

    前言 我本来是打算写一篇co源码精读(为啥读co,因为它短),然鹅发现自己存在一系列基础问题没有搞透彻,打算写一个js基础系列文章,总结自己的理解(copy),希望与你在学习路上一同进步.首先问问自己当面试官问到js中的同步和异步,这个问题该怎么回答?理解一个问题无非是what-why-how js同步和异步问题是什么-->为什么会产生异步问题-->如何解决. 一.JavaScript起源 技术的出现,和应用场景密切相关的.JavaScript诞生于1995年.当时,它的主要目的是处理以前由服

随机推荐