开发了一个树结构数组、扁平化数组相互转换的工具

Github:github.com/huyikai/tre...

Tree-Conver 是一个能将扁平节点数组与树形数组相互转换的工具。

对外导出 arrayToTreetreeToArray 两个方法。两个方法的基础情况下时间和空间复杂度均为 O(n),测试10w内数据的表现良好

treeToArray 方法增加了参数 addFieldsignoreFields,可以灵活的增减处理后数据中的字段。

安装使用

shell 复制代码
npm i tree-conver
javascript 复制代码
import { treeToArray, arrayToTree } from 'tree-conver';

数组转树

将一个扁平的节点数组转换成树形结构。

参数

它接受两个参数:

  • Array: 扁平的节点数组

  • Options: 一个可选的参数对象,用于配置转换方法的具体行为

    参数 描述 类型 默认值
    childrenKey 自定义节点 children 字段名称 string 'children'
    idKey 自定义节点 ID 字段名称 string 'id'
    pidKey 自定义节点父 ID 字段名称 string 'pid'

示例

javascript 复制代码
const flatArray = [
  { uid: '1', name: 'node1', pid: null },
  { uid: '2', name: 'node2', pid: '1' },
  { uid: '3', name: 'node3', pid: '1' },
  { uid: '4', name: 'node4', pid: '2' },
  { uid: '5', name: 'node5', pid: '2' },
  { uid: '6', name: 'node6', pid: '3' }
];

const options = {
  idKey: 'id',
  pidKey: 'pid',
  childrenKey: 'children'
};

const treeArray = arrayToTree(flatArray, options);

实现代码

typescript 复制代码
interface Node {
  id: string;
  children?: Array<Node>;
  pid?: string;
}
interface Options {
  idKey?: string;
  pidKey?: string;
  childrenKey?: string;
}

export const arrayToTree = (
  array: Array<Node | undefined>,
  options: Options = {}
) => {
  if (!Array.isArray(array)) {
    throw new Error('The first argument must be an array.');
  }
  const { idKey = 'id', pidKey = 'pid', childrenKey = 'children' } = options;
  const map = array.reduce((acc: Record<string, Node>, node: any) => {
    acc[node[idKey]] = { ...node, [childrenKey]: [] };
    return acc;
  }, {});

  Object.values(map).forEach((node: any) => {
    const parentId = node[pidKey];
    if (parentId) {
      const parent: any = map[parentId];
      if (!parent[childrenKey]) {
        parent[childrenKey] = [];
      }
      parent[childrenKey].push(node);
    }
  });
  const tree = Object.values(map).filter((node: any) => !node[pidKey]);
  return tree;
};

树转数组

将树形结构的数据转换为扁平的数组。

参数

接受两个参数:

  • Tree: 树形结构数组

  • Options: 一个可选的参数对象,用于配置转换方法的具体行为

    属性 描述 类型 默认值
    addFields 需要添加的字段名称及其对应的属性值计算方法的列表 [{ fieldName: string;callback: (item) => any }] []
    childrenKey 子节点的键名 string 'children'
    ignoreFields 要忽略的字段名称列表 string[] []
    needParentId 是否添加节点信息的父节点 ID boolean true

示例

javascript 复制代码
const treeArray = [
  {
    id: '1',
    name: 'Node 1',
    list: [
      {
        id: '2',
        name: 'Node 2',
        list: [
          {
            id: '3',
            name: 'Node 3'
          }
        ]
      },
      {
        id: '4',
        name: 'Node 4'
      }
    ]
  }
];
const calculateDepth = (node) => {
  let depth = 0;
  let parent = node;
  while (parent) {
    depth++;
    parent =
      parent['parentId'] && treeArray.find((n) => n.id === parent['parentId']);
  }
  return depth;
};
const options = {
  childrenKey: 'list',
  ignoreFields: [],
  addFields: [
    {
      fieldName: 'hasChildren', // Add a new 'field' property with a boolean value
      callback: (node) => Boolean(node['children'])
    },
    {
      fieldName: 'depth', // Add a new 'depth' property with the depth of each node
      callback: calculateDepth
    }
  ],
  needParentId: true
};

const flatArray = treeToArray(treeArray, options);

console.log(flatArray);
[
    {
      "id": "1",
      "name": "Node 1",
      "parentId": "",
      "hasChildren": false,
      "depth": 1
    },
    {
      "id": "2",
      "name": "Node 2",
      "parentId": "1",
      "hasChildren": false,
      "depth": 1
    },
    {
      "id": "3",
      "name": "Node 3",
      "parentId": "2",
      "hasChildren": false,
      "depth": 1
    },
    {
      "id": "4",
      "name": "Node 4",
      "parentId": "1",
      "hasChildren": false,
      "depth": 1
    }
]

实现代码

typescript 复制代码
interface Node {
  [key: string]: any;
  children?: Array<Node>;
}

interface TreeToArrayOptions {
  childrenKey?: string;
  ignoreFields?: Array<string>;
  addFields?: Array<{ fieldName: string; callback: (item: Node) => any }>;
  needParentId?: boolean;
}

export const treeToArray = (
  tree: Array<Node>,
  options: TreeToArrayOptions = {}
): Array<Node> => {
  const {
    childrenKey = 'children',
    ignoreFields = []
    addFields = [],
    needParentId = true
  } = options;
  const nodes: Array<Node> = [];
  const stack: Array<{
    node: Node | null;
    children: Array<Node>;
    parentId: string | null;
  }> = [];
  stack.push({
    node: null,
    children: tree,
    parentId: null
  });
  while (stack.length) {
    const { node, children, parentId } = stack.pop()!;
    if (node) {
      const { [childrenKey]: subChildren, ...rest } = node;
      const newNode = { ...rest };
      if (needParentId) {
        newNode['parentId'] = parentId;
      }
      if (addFields.length) {
        for (let i = 0; i < addFields.length; i++) {
          newNode[addFields[i].fieldName] = addFields[i].callback(node);
        }
      }
      if (ignoreFields.length) {
        for (let i = 0; i < ignoreFields.length; i++) {
          delete newNode[ignoreFields[i]];
        }
      }
      nodes.push(newNode);
    }
    if (children) {
      for (let i = children.length - 1; i >= 0; i--) {
        stack.push({
          node: children[i],
          children: children[i][childrenKey] || [],
          parentId: node?.id || ''
        });
      }
    }
  }
  return nodes;
};
相关推荐
小远yyds8 分钟前
前端Web用户 token 持久化
开发语言·前端·javascript·vue.js
AI街潜水的八角29 分钟前
基于C++的决策树C4.5机器学习算法(不调包)
c++·算法·决策树·机器学习
白榆maple1 小时前
(蓝桥杯C/C++)——基础算法(下)
算法
阿伟来咯~1 小时前
记录学习react的一些内容
javascript·学习·react.js
JSU_曾是此间年少1 小时前
数据结构——线性表与链表
数据结构·c++·算法
吕彬-前端1 小时前
使用vite+react+ts+Ant Design开发后台管理项目(五)
前端·javascript·react.js
学前端的小朱1 小时前
Redux的简介及其在React中的应用
前端·javascript·react.js·redux·store
guai_guai_guai1 小时前
uniapp
前端·javascript·vue.js·uni-app
也无晴也无风雨1 小时前
在JS中, 0 == [0] 吗
开发语言·javascript
此生只爱蛋2 小时前
【手撕排序2】快速排序
c语言·c++·算法·排序算法