Skip to content

Commit

Permalink
feat(TreeData): 新增 filter 方法筛选符合条件的节点
Browse files Browse the repository at this point in the history
  • Loading branch information
fjc0k committed Dec 14, 2020
1 parent 66cf34d commit df07544
Show file tree
Hide file tree
Showing 3 changed files with 394 additions and 88 deletions.
33 changes: 25 additions & 8 deletions src/utils/TreeData.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,23 @@ describe('TreeData', () => {
expect(new TreeData(data).pickNodeProps(['id']).export()).toMatchSnapshot()
})

test('filter', () => {
expect(
new TreeData(data).filter(_ => _.node.id.endsWith('.2')).export(),
).toMatchSnapshot()
expect(
new TreeData(data)
.filter(_ => _.node.id.endsWith('.2'))
.filter(_ => _.node.id.startsWith('1.'))
.export(),
).toMatchSnapshot()
expect(
new TreeData(data)
.filter(_ => _.node.id.endsWith('.2') || _.node.id === '1')
.export(),
).toMatchSnapshot()
})

test('setDepth', () => {
expect(new TreeData(data).setDepth(0).export()).toMatchSnapshot()
})
Expand All @@ -107,12 +124,12 @@ describe('TreeData', () => {
).toMatchSnapshot()
})

test('findNodes', () => {
test('findNodeAll', () => {
expect(
new TreeData(data).findNodes(_ => _.node.id.startsWith('1.')),
new TreeData(data).findNodeAll(_ => _.node.id.startsWith('1.')),
).toMatchSnapshot()
expect(
new TreeData(data).findNodes(_ => _.node.id.startsWith('1.3333')),
new TreeData(data).findNodeAll(_ => _.node.id.startsWith('1.3333')),
).toMatchSnapshot()
})

Expand All @@ -125,12 +142,12 @@ describe('TreeData', () => {
).toMatchSnapshot()
})

test('findNodePaths', () => {
test('findNodePathAll', () => {
expect(
new TreeData(data).findNodePaths(_ => _.node.id === '1.1'),
new TreeData(data).findNodePathAll(_ => _.node.id === '1.1'),
).toMatchSnapshot()
expect(
new TreeData(data).findNodePaths(_ => _.node.id === '1.1111'),
new TreeData(data).findNodePathAll(_ => _.node.id === '1.1111'),
).toMatchSnapshot()
})

Expand All @@ -141,9 +158,9 @@ describe('TreeData', () => {
expect(tree.export()).toMatchSnapshot()
})

test('removeNodes', () => {
test('removeNodeAll', () => {
const tree = new TreeData(data)
const removed = tree.removeNodes(_ => _.node.id.startsWith('1.'))
const removed = tree.removeNodeAll(_ => _.node.id.startsWith('1.'))
expect(removed).toMatchSnapshot()
expect(tree.export()).toMatchSnapshot()
})
Expand Down
107 changes: 78 additions & 29 deletions src/utils/TreeData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ export interface TreeDataTraverseFnPayload<TNode extends TreeDataNode> {
* 退出遍历。
*/
exit: () => void

/**
* 跳过子树遍历。
*/
skipChildrenTraverse: () => void
}

export type TreeDataTraverseFn<TNode extends TreeDataNode> = (
Expand Down Expand Up @@ -115,12 +120,14 @@ export class TreeData<TNode extends TreeDataNode> {
path: TNode[],
) {
const removeNodeIndexes: number[] = []
const skipChildrenTraverseNodeIndexes: number[] = []

for (let i = 0, len = data.length; i < len; i++) {
const node = data[i]

let isRemove = false
let isExit = false
let isSkipChildrenTraverse = false

fn({
node: node,
Expand All @@ -132,25 +139,31 @@ export class TreeData<TNode extends TreeDataNode> {
removeNodeIndexes.push(i)
},
exit: () => (isExit = true),
skipChildrenTraverse: () => {
isSkipChildrenTraverse = true
skipChildrenTraverseNodeIndexes.push(i)
},
})

if (isExit) return

if (searchStrategy === 'DFS') {
if (
!isRemove &&
node[childrenPropName] &&
Array.isArray(node[childrenPropName])
) {
TreeData.traverse(
node[childrenPropName],
childrenPropName,
node,
fn,
searchStrategy,
depth + 1,
path.concat(node),
)
if (!isSkipChildrenTraverse) {
if (searchStrategy === 'DFS') {
if (
!isRemove &&
node[childrenPropName] &&
Array.isArray(node[childrenPropName])
) {
TreeData.traverse(
node[childrenPropName],
childrenPropName,
node,
fn,
searchStrategy,
depth + 1,
path.concat(node),
)
}
}
}
}
Expand All @@ -161,17 +174,20 @@ export class TreeData<TNode extends TreeDataNode> {
}

if (searchStrategy === 'BFS') {
for (const node of data) {
if (node[childrenPropName] && Array.isArray(node[childrenPropName])) {
TreeData.traverse(
node[childrenPropName],
childrenPropName,
node,
fn,
searchStrategy,
depth + 1,
path.concat(node),
)
for (let i = 0, len = data.length; i < len; i++) {
if (skipChildrenTraverseNodeIndexes.indexOf(i) === -1) {
const node = data[i]
if (node[childrenPropName] && Array.isArray(node[childrenPropName])) {
TreeData.traverse(
node[childrenPropName],
childrenPropName,
node,
fn,
searchStrategy,
depth + 1,
path.concat(node),
)
}
}
}
}
Expand Down Expand Up @@ -299,6 +315,39 @@ export class TreeData<TNode extends TreeDataNode> {
return this as any
}

/**
* 筛选符合条件的节点。
*
* @param predicate 条件
*/
filter(
predicate: (payload: TreeDataTraverseFnPayload<TNode>) => boolean,
): this {
this.traverse([
payload => {
if (predicate(payload)) {
;(payload.node as any).__SKIP__ = true
;(payload.node as any).__PICK__ = true
for (const node of payload.path) {
;(node as any).__PICK__ = true
}
payload.skipChildrenTraverse()
}
},
payload => {
if (payload.node.__SKIP__ === true) {
payload.skipChildrenTraverse()
}
if (payload.node.__PICK__ !== true) {
payload.removeNode()
}
delete payload.node.__SKIP__
delete payload.node.__PICK__
},
])
return this
}

/**
* 查找符合条件的第一个节点。
*
Expand All @@ -322,7 +371,7 @@ export class TreeData<TNode extends TreeDataNode> {
*
* @param predicate 条件
*/
findNodes(
findNodeAll(
predicate: (payload: TreeDataTraverseFnPayload<TNode>) => boolean,
): TNode[] {
const nodes: TNode[] = []
Expand Down Expand Up @@ -357,7 +406,7 @@ export class TreeData<TNode extends TreeDataNode> {
*
* @param predicate 条件
*/
findNodePaths(
findNodePathAll(
predicate: (payload: TreeDataTraverseFnPayload<TNode>) => boolean,
): Array<TNode[]> {
const paths: Array<TNode[]> = []
Expand Down Expand Up @@ -393,7 +442,7 @@ export class TreeData<TNode extends TreeDataNode> {
*
* @param predicate 条件
*/
removeNodes(
removeNodeAll(
predicate: (payload: TreeDataTraverseFnPayload<TNode>) => boolean,
): TNode[] {
const nodes: TNode[] = []
Expand Down
Loading

0 comments on commit df07544

Please sign in to comment.