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 数组中。
最后,我们从扁平数组中筛选出 parentIdnull 的节点,这是树的根节点。然后调用递归构建函数 buildTree 来创建整棵树,并将这些树形结构的根节点集合作为最终结果。

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

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 函数内部,如果当前节点有子节点,则对其每个子节点进行同样的遍历操作。
最后返回扁平数组。

总结

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

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 使用JavaScript实现模拟数组数据最简单的方法就是使用Array对象,它允许你创建一个模拟数组,并使用一些方法来操作它。例如,可以使用Array.push()方法向模拟数组中添加新的数据项,也可以使用Array.pop()方法从模拟数组中删除数据项,以及Array.shift()方法从模拟数组中移除第一个元素。此外,也可以使用Array.forEach()方法对模拟数组中的每个元素执行指定的操作。 ### 回答2: 使用JavaScript可以很方便地实现模拟数组数据。我们可以使用数组相关的方法和属性,来操作和处理这些模拟的数据。 首先,我们可以创建一个空的数组,使用如下代码进行初始化: ```javascript let mockArray = []; ``` 然后,我们可以使用push方法向数组中添加元素: ```javascript mockArray.push(1); // 添加元素1 mockArray.push(2); // 添加元素2 ``` 我们也可以使用length属性获取数组的长度,通过访问数组下标来获取特定位置的元素: ```javascript console.log(mockArray.length); // 输出数组长度,结果为2 console.log(mockArray[0]); // 输出第一个元素,结果为1 ``` 此外,我们还可以使用pop方法删除数组中的最后一个元素: ```javascript mockArray.pop(); // 删除最后一个元素 console.log(mockArray.length); // 输出数组长度,结果为1 ``` 我们可以使用forEach方法遍历数组中的每一个元素: ```javascript mockArray.forEach(function(element) { console.log(element); // 输出每一个元素 }); ``` 我们还可以使用一些其他的方法和属性,如shift、unshift、slice、splice等,来操作和处理模拟的数组数据。 总之,通过使用JavaScript提供的数组相关的方法和属性,我们可以很方便地实现模拟数组数据,实现各种对数组的操作和处理。 ### 回答3: JavaScript数组是一种用于储存多个值的数据结构。可以通过声明一个变量并使用方括号([])表示法来创建一个数组。下面是使用JavaScript实现模拟数组数据的一种方法。 首先,我们可以声明一个变量并将其赋值为空数组。例如: ``` let myArray = []; ``` 然后,我们可以使用JavaScript的`push()`方法向数组中添加元素。例如: ``` myArray.push(1); myArray.push(2); myArray.push(3); ``` 我们也可以使用`length`属性获取数组的长度。例如: ``` console.log(myArray.length); // 输出3 ``` 要访问数组中的元素,可以使用方括号([])表示法加上索引值来引用元素。索引值从0开始。例如: ``` console.log(myArray[0]); // 输出1 console.log(myArray[1]); // 输出2 console.log(myArray[2]); // 输出3 ``` 我们还可以使用`pop()`方法从数组中删除最后一个元素。例如: ``` myArray.pop(); console.log(myArray); // 输出[1, 2] console.log(myArray.length); // 输出2 ``` 此外,我们还可以使用循环来遍历数组中的元素。例如,使用`for`循环: ``` for (let i = 0; i < myArray.length; i++) { console.log(myArray[i]); } ``` 这些是使用JavaScript实现模拟数组数据的基本方法。当然,JavaScript提供了更多的数组操作方法,例如`splice()`、`slice()`等,可以根据需要进行学习和使用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值