JS将一个具有父子关系的一维数组转换为树形结构

JS将一个具有父子关系的一维数组转换为树形结构

// 数据项中,parentId指当前菜单的父菜单项的id。
const data = [
  { id: 1, title: '系统管理', parentId: 0 },
  { id: 2, title: '用户管理', parentId: 1 },
  { id: 3, title: '角色管理', parentId: 1 },
  { id: 4, title: '菜单管理', parentId: 1 },
  { id: 5, title: '字典管理', parentId: 1 },
  { id: 6, title: '编码规则管理', parentId: 1 },
  { id: 7, title: '个人中心', parentId: 0 },
  { id: 8, title: '个人资料', parentId: 7 },
  { id: 9, title: '我的消息', parentId: 7 },
  { id: 10, title: '菜单1', parentId: 0 },
  { id: 11, title: '菜单1-1', parentId: 10 },
  { id: 12, title: '菜单1-2', parentId: 10 },
  { id: 13, title: '菜单1-2-1', parentId: 12 },
  { id: 14, title: '菜单1-2-2', parentId: 12 },
  { id: 15, title: '菜单1-2-3', parentId: 12 }
]

转换结果

[
  {
    "id": 1,
    "title": "系统管理",
    "parentId": 0,
    "children": [
      {
        "id": 2,
        "title": "用户管理",
        "parentId": 1,
        "children": []
      },
      {
        "id": 3,
        "title": "角色管理",
        "parentId": 1,
        "children": []
      },
      {
        "id": 4,
        "title": "菜单管理",
        "parentId": 1,
        "children": []
      },
      {
        "id": 5,
        "title": "字典管理",
        "parentId": 1,
        "children": []
      },
      {
        "id": 6,
        "title": "编码规则管理",
        "parentId": 1,
        "children": []
      }
    ]
  },
  {
    "id": 7,
    "title": "个人中心",
    "parentId": 0,
    "children": [
      {
        "id": 8,
        "title": "个人资料",
        "parentId": 7,
        "children": []
      },
      {
        "id": 9,
        "title": "我的消息",
        "parentId": 7,
        "children": []
      }
    ]
  },
  {
    "id": 10,
    "title": "菜单1",
    "parentId": 0,
    "children": [
      {
        "id": 11,
        "title": "菜单1-1",
        "parentId": 10,
        "children": []
      },
      {
        "id": 12,
        "title": "菜单1-2",
        "parentId": 10,
        "children": [
          {
            "id": 13,
            "title": "菜单1-2-1",
            "parentId": 12,
            "children": []
          },
          {
            "id": 14,
            "title": "菜单1-2-2",
            "parentId": 12,
            "children": []
          },
          {
            "id": 15,
            "title": "菜单1-2-3",
            "parentId": 12,
            "children": []
          }
        ]
      }
    ]
  }
]

思路1:递归方式

  • 首先定义一个 children 数组,用于存储所有与指定父节点 ID 匹配的子节点;
  • 然后遍历整个数组,查找与指定父节点 ID 匹配的所有子节点;
  • 对于每个匹配的子节点,递归调用 toTree 函数,传递当前子节点的 ID 作为新的父节点 ID,以获取当前子节点的所有子节点;
  • 最后将所有子节点添加到 children 数组中,并返回结果数组。
function toTree(arr, parentId) {
  if (!arr.length) {
    return [];
  }
  
  // 定义一个 children 数组
  const children = [];
  
  for (const node of arr) {
    if (node.parentId === parentId) {
      const child = { ...node };
      // 对于每个匹配的子节点,递归调用 toTree 函数,传递当前子节点的 ID 作为新的父节点 ID,以获取当前子节点的所有子节点。
      child.children = toTree(arr, node.id);
      children.push(child);
    }
  }
  return children;
}

// 测试代码
const tree = toTree(data, 0);
console.log(tree);

思路2:非递归方式

  • 首先创建一个空数组 tree 用于存储树形结构,同时创建一个 Map 对象 map 用于存储每个节点的子节点信息;
  • 遍历数组中的每个节点,将其作为 map 中的一个数据项存储。此时每个节点的 children 属性被初始化为空数组;
  • 再次遍历 map 中的每个节点。对于每个节点,获取其父节点 ID 并从 map 中查找父节点。如果找到父节点,则将该节点添加为父节点的子节点;否则将该节点添加到根节点数组 tree 中;
  • 完成所有节点的处理后,返回 tree 数组作为结果。
function toTree(arr) {
  const tree = [];
  const map = new Map();

  arr.forEach(node => {
    map.set(node.id, { ...node, children: [] });
  });

  map.forEach((node, _, map) => {
    const parentId = node.parentId;
    const parent = map.get(parentId);

    if (parent) {
      parent.children.push(node);
    } else {
      tree.push(node);
    }
  });

  return tree;
}

// 测试代码
const tree = toTree(data);
console.log(tree);

如何选择?

虽然递归方式实现简单,但时间复杂度和空间复杂度都较高,不适用于处理大规模的数据集。相比之下,非递归方式具有更好的性能和可扩展性,适合处理大规模的数据集。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值