From 8b5715c746e4b28d213b7fdcc9b1a5583efb8966 Mon Sep 17 00:00:00 2001 From: karlsbeard <255775675@qq.com> Date: Mon, 26 Aug 2024 21:46:37 +0800 Subject: [PATCH] feat: add the path find function --- src/index.ts | 178 ++++++++++++++++++++++++++++++++++++++++-- test/findPath.spec.ts | 78 ++++++++++++++++++ 2 files changed, 249 insertions(+), 7 deletions(-) create mode 100644 test/findPath.spec.ts diff --git a/src/index.ts b/src/index.ts index 7f51fe2..adc4758 100644 --- a/src/index.ts +++ b/src/index.ts @@ -77,13 +77,36 @@ export const TTs = { * @param id the id which you want to find * @returns return the node */ - findNodeById(tree: BaseTreeNode[], id: string | number): BaseTreeNode | null { + findNodeByIdBFS(tree: T[], id: string | number): T | null { + if (!tree.length) + return null + + const queue: T[] = [...tree] + + while (queue.length) { + const node = queue.shift() + + if (node?.id === id) { + return node + } + + if (node?.children) { + queue.push(...node.children as T[]) + } + } + + return null + }, + + findNodeByIdDFS(tree: T[], id: string | number): T | null { for (const node of tree) { if (node.id === id) { return node } + if (node.children) { - const result = TTs.findNodeById(node.children, id) + const children = node.children as T[] + const result = TTs.findNodeByIdDFS(children, id) if (result) { return result } @@ -97,13 +120,14 @@ export const TTs = { * @param tree the tree structure */ - findNodeByFunc(tree: BaseTreeNode[], func: (node: BaseTreeNode) => boolean): BaseTreeNode | null { + findNodeByFunc(tree: T[], func: (node: T) => boolean): T | null { for (const node of tree) { if (func(node)) { return node } if (node.children) { - const result = TTs.findNodeByFunc(node.children, func) + const children = node.children as T[] + const result = TTs.findNodeByFunc(children, func) if (result) { return result } @@ -117,18 +141,158 @@ export const TTs = { * @param tree the tree structure */ - findAllNode(tree: BaseTreeNode[], func: (node: BaseTreeNode) => boolean): BaseTreeNode[] { - const result: BaseTreeNode[] = [] + findAllNode(tree: T[], func: (node: T) => boolean): T[] { + const result: T[] = [] for (const node of tree) { if (func(node)) { result.push(node) } if (node.children) { - result.push(...TTs.findAllNode(node.children, func)) + const children = node.children as T[] + result.push(...TTs.findAllNode(children, func)) } } return result }, + + /** + * @description find the first path by id in the tree + * @param tree the tree structure + * @param id the id which you want to find + * @returns return the path + */ + + findPathByIdBFS(tree: T[], id: string | number): T[] | null { + if (!tree.length) + return null + + const queue: { node: T, path: T[] }[] = [] + + for (const node of tree) { + queue.push({ node, path: [node] }) + } + + while (queue.length) { + const { node, path } = queue.shift()! + if (node.id === id) { + return path + } + + if (node.children) { + const children = node.children as T[] + for (const child of children) { + queue.push({ node: child, path: [...path, child] }) + } + } + } + + return null + }, + + findPathByIdDFS(tree: T[], id: string | number): T[] | null { + const path: T[] = [] + + function dfs(nodes: T[]): boolean { + for (const node of nodes) { + path.push(node) + if (node.id === id) { + return true + } + if (node.children) { + const children = node.children as T[] + if (dfs(children)) { + return true + } + } + path.pop() + } + return false + } + + return dfs(tree) ? path : null + }, + + /** + * @description find the first path by func in the tree within BFS + * @param tree the tree structure + * @param func the function which you want to find + * @returns return the path, maybe the null + */ + + findPathByFuncBFS(tree: T[], func: (node: T) => boolean): T[] | null { + const path: T[] = [] + const list: T[] = [...tree] + const visitedSet = new Set() + + while (list.length) { + const node = list[0] + if (visitedSet.has(node)) { + path.pop() + list.shift() + } + else { + visitedSet.add(node) + const children = node.children as T[] | undefined + if (children) { + list.unshift(...children) + } + path.push(node) + if (func(node)) { + return path + } + } + } + return null + }, + + /** + * @description find the first path by func in the tree within DFS + * @param tree the tree structure + * @param func the function which you want to find + * @returns return the path + */ + + findPathByFuncDFS(tree: T[], func: (node: T) => boolean): T[] | null { + const path: T[] = [] + for (const node of tree) { + if (func(node)) { + return path + } + if (node.children) { + const children = node.children as T[] + const path = TTs.findPathByFuncDFS(children, func) + if (path) { + return path + } + } + } + return null + }, + + /** + * @description find all path by func in the tree + * @param tree the tree structure + * @param func the function which you want to find + * @returns all path which you want to find + */ + + findPathAll(tree: T[], func: (node: T) => boolean): T[][] { + const allPath: T[][] = [] + for (const node of tree) { + if (func(node)) { + allPath.push([node]) + } + if (node.children) { + const children = node.children as T[] + const childPaths = TTs.findPathAll(children, func) + for (const childPath of childPaths) { + allPath.push([node, ...childPath]) + } + } + } + return allPath + }, + } // TODO: setting your own tree config diff --git a/test/findPath.spec.ts b/test/findPath.spec.ts new file mode 100644 index 0000000..d87b810 --- /dev/null +++ b/test/findPath.spec.ts @@ -0,0 +1,78 @@ +import { describe, expect, it } from 'vitest' +import { TTs } from '@/index' + +const { findPathAll, findPathByFuncBFS, findPathByIdBFS } = TTs + +describe('findPath', () => { + it('findPathAll', () => { + const tree = [ + { + id: 1, + pid: null, + children: [ + { + id: 2, + pid: 1, + children: [ + { + id: 3, + pid: 2, + }, + ], + }, + ], + }, + ] + const labelRes = [[tree[0], tree[0].children![0], tree[0].children![0].children![0]]] + const result = findPathAll(tree, node => node.id === 3) + expect(result).toEqual(labelRes) + }) + + it('findPathByFuncBFS', () => { + const tree = [ + { + id: 1, + pid: null, + children: [ + { + id: 2, + pid: 1, + children: [ + { + id: 3, + pid: 2, + }, + ], + }, + ], + }, + ] + const labelRes = [tree[0], tree[0].children![0], tree[0].children![0].children![0]] + const result = findPathByFuncBFS(tree, node => node.id === 3) + expect(result).toEqual(labelRes) + }) + + it('findPathById', () => { + const tree = [ + { + id: 1, + pid: null, + children: [ + { + id: 2, + pid: 1, + children: [ + { + id: 3, + pid: 2, + }, + ], + }, + ], + }, + ] + const labelRes = [tree[0].children![0].children![0]] + const result = findPathByIdBFS(tree, 3) + expect(result).toEqual(labelRes) + }) +})