Skip to content

Commit

Permalink
feat: add the path find function
Browse files Browse the repository at this point in the history
  • Loading branch information
karlsbeard committed Aug 26, 2024
1 parent 76f0bd8 commit 8b5715c
Show file tree
Hide file tree
Showing 2 changed files with 249 additions and 7 deletions.
178 changes: 171 additions & 7 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<T extends BaseTreeNode>(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<T extends BaseTreeNode>(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
}
Expand All @@ -97,13 +120,14 @@ export const TTs = {
* @param tree the tree structure
*/

findNodeByFunc(tree: BaseTreeNode[], func: (node: BaseTreeNode) => boolean): BaseTreeNode | null {
findNodeByFunc<T extends BaseTreeNode>(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
}
Expand All @@ -117,18 +141,158 @@ export const TTs = {
* @param tree the tree structure
*/

findAllNode(tree: BaseTreeNode[], func: (node: BaseTreeNode) => boolean): BaseTreeNode[] {
const result: BaseTreeNode[] = []
findAllNode<T extends BaseTreeNode>(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<T extends BaseTreeNode>(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<T extends BaseTreeNode>(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<T extends BaseTreeNode>(tree: T[], func: (node: T) => boolean): T[] | null {
const path: T[] = []
const list: T[] = [...tree]
const visitedSet = new Set<T>()

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<T extends BaseTreeNode>(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<T extends BaseTreeNode>(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
Expand Down
78 changes: 78 additions & 0 deletions test/findPath.spec.ts
Original file line number Diff line number Diff line change
@@ -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)
})
})

0 comments on commit 8b5715c

Please sign in to comment.