tree-processor 0.9.7 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +759 -39
- package/README.md +759 -40
- package/dist/.tsbuildinfo +1 -1
- package/dist/index.d.ts +95 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/stats.html +1 -1
- package/dist/tree-processor.cjs.js +116 -38
- package/dist/tree-processor.esm.js +117 -39
- package/dist/tree-processor.umd.js +174 -96
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -9,12 +9,12 @@
|
|
|
9
9
|
<div align="center">
|
|
10
10
|
|
|
11
11
|

|
|
12
|
-
](https://img.shields.io/badge/downloads-1.7K%2F2mo-brightgreen?style=flat-square)
|
|
13
|
+

|
|
14
14
|

|
|
15
15
|

|
|
16
16
|
|
|
17
|
-
一个轻量级的树结构数据处理工具库,使用 TypeScript
|
|
17
|
+
一个轻量级的树结构数据处理工具库,使用 TypeScript 编写,提供50+ API,包括遍历、查找、修改、转换、查询、分析、验证等完整功能。
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
</div>
|
|
@@ -26,28 +26,26 @@
|
|
|
26
26
|
- [安装](#-安装)
|
|
27
27
|
- [快速开始](#-快速开始)
|
|
28
28
|
- [API 文档](#-api-文档)
|
|
29
|
-
- [
|
|
30
|
-
- [
|
|
31
|
-
- [
|
|
32
|
-
- [
|
|
33
|
-
- [
|
|
34
|
-
- [
|
|
35
|
-
- [
|
|
29
|
+
- [遍历操作方法](#遍历操作方法)
|
|
30
|
+
- [条件查找方法](#条件查找方法)
|
|
31
|
+
- [索引访问方法](#索引访问方法)
|
|
32
|
+
- [节点操作方法](#节点操作方法)
|
|
33
|
+
- [格式转换方法](#格式转换方法)
|
|
34
|
+
- [克隆复制方法](#克隆复制方法)
|
|
35
|
+
- [关系查询方法](#关系查询方法)
|
|
36
|
+
- [数据验证方法](#数据验证方法)
|
|
37
|
+
- [聚合分析方法](#聚合分析方法)
|
|
36
38
|
- [自定义字段名](#自定义字段名)
|
|
37
39
|
- [测试](#测试)
|
|
38
40
|
- [开发](#开发)
|
|
39
41
|
|
|
40
42
|
## ✨ 特性
|
|
41
43
|
|
|
42
|
-
-
|
|
43
|
-
-
|
|
44
|
-
-
|
|
45
|
-
-
|
|
46
|
-
-
|
|
47
|
-
- **完善的测试覆盖** - 包含 328 个测试用例,测试覆盖率达到 99%+(语句覆盖率 99%,分支覆盖率 98.41%,函数覆盖率 100%,行覆盖率 98.99%),覆盖基础功能、边界情况、异常处理、复杂场景等
|
|
48
|
-
- **丰富的 API** - 提供 32+ 个方法,包含类似数组的 API(map、filter、find、some、every等),以及树结构特有的操作(获取父子节点、深度计算、数据验证、格式转换等),涵盖遍历、查找、修改、转换、判断等完整场景
|
|
49
|
-
|
|
50
|
-
**已支持的方法:** mapTree、forEachTree、filterTree、findTree、pushTree、unshiftTree、popTree、shiftTree、someTree、everyTree、includesTree、atTree、indexOfTree、atIndexOfTree、dedupTree、removeTree、getParentTree、getChildrenTree、getSiblingsTree、getNodeDepthMap、getNodeDepth、isLeafNode、isRootNode、isEmptyTreeData、isEmptySingleTreeData、isTreeData、isSingleTreeData、isValidTreeNode、isTreeNodeWithCircularCheck、isSafeTreeDepth、convertToArrayTree、convertBackTree、convertToMapTree、convertToLevelArrayTree、convertToObjectTree。每个方法的最后一个参数可以自定义 children 和 id 的属性名。
|
|
44
|
+
- **多格式支持** - 提供 ESM、CJS、UMD 格式,体积仅 14.9-15.2 KB,支持 Tree-shaking,按需导入
|
|
45
|
+
- **零依赖** - 无外部依赖,开箱即用
|
|
46
|
+
- **高性能** - 中等规模树(~120节点)平均执行时间 < 0.03ms
|
|
47
|
+
- **功能完整** - 50+ API,覆盖遍历、查找、修改、转换、查询、分析、验证等完整功能
|
|
48
|
+
- **测试完善** - 447 个测试用例,99%+ 覆盖率
|
|
51
49
|
|
|
52
50
|
### 💡 使用场景
|
|
53
51
|
|
|
@@ -153,7 +151,9 @@ const treeData = [
|
|
|
153
151
|
|
|
154
152
|
---
|
|
155
153
|
|
|
156
|
-
##
|
|
154
|
+
## 遍历操作方法
|
|
155
|
+
|
|
156
|
+
遍历树结构数据并对每个节点执行操作的方法。
|
|
157
157
|
|
|
158
158
|
### mapTree
|
|
159
159
|
|
|
@@ -202,7 +202,9 @@ console.log(nodeCount) // 节点总数
|
|
|
202
202
|
|
|
203
203
|
---
|
|
204
204
|
|
|
205
|
-
##
|
|
205
|
+
## 条件查找方法
|
|
206
|
+
|
|
207
|
+
通过条件或谓词函数查找节点的方法。
|
|
206
208
|
|
|
207
209
|
### filterTree
|
|
208
210
|
|
|
@@ -285,7 +287,9 @@ console.log(allHaveName) // 根据实际数据返回 true 或 false
|
|
|
285
287
|
|
|
286
288
|
---
|
|
287
289
|
|
|
288
|
-
##
|
|
290
|
+
## 索引访问方法
|
|
291
|
+
|
|
292
|
+
通过位置索引或索引路径访问节点的方法。
|
|
289
293
|
|
|
290
294
|
### atTree
|
|
291
295
|
|
|
@@ -345,7 +349,9 @@ console.log(invalidPath) // null
|
|
|
345
349
|
|
|
346
350
|
---
|
|
347
351
|
|
|
348
|
-
##
|
|
352
|
+
## 节点操作方法
|
|
353
|
+
|
|
354
|
+
对树结构进行增删改操作的方法(添加、删除、移除节点等)。
|
|
349
355
|
|
|
350
356
|
### pushTree
|
|
351
357
|
|
|
@@ -375,26 +381,30 @@ console.log(treeData) // 新节点已添加到 children 数组开头
|
|
|
375
381
|
|
|
376
382
|
### popTree
|
|
377
383
|
|
|
378
|
-
删除指定节点下的最后一个子节点。返回被删除的节点,如果节点不存在或没有子节点则返回
|
|
384
|
+
删除指定节点下的最后一个子节点。返回被删除的节点,如果节点不存在或没有子节点则返回 null。
|
|
379
385
|
|
|
380
386
|
```javascript
|
|
381
387
|
// 删除ID为1的节点下的最后一个子节点
|
|
382
388
|
const removedNode = t.popTree(treeData, 1)
|
|
383
|
-
console.log(removedNode) // 返回被删除的节点对象,或
|
|
389
|
+
console.log(removedNode) // 返回被删除的节点对象,或 null
|
|
384
390
|
|
|
385
391
|
// 尝试删除不存在的节点下的子节点
|
|
386
392
|
const popFailed = t.popTree(treeData, 999)
|
|
387
|
-
console.log(popFailed) //
|
|
393
|
+
console.log(popFailed) // null
|
|
388
394
|
```
|
|
389
395
|
|
|
390
396
|
### shiftTree
|
|
391
397
|
|
|
392
|
-
删除指定节点下的第一个子节点。返回被删除的节点,如果节点不存在或没有子节点则返回
|
|
398
|
+
删除指定节点下的第一个子节点。返回被删除的节点,如果节点不存在或没有子节点则返回 null。
|
|
393
399
|
|
|
394
400
|
```javascript
|
|
395
401
|
// 删除ID为1的节点下的第一个子节点
|
|
396
402
|
const shiftedNode = t.shiftTree(treeData, 1)
|
|
397
|
-
console.log(shiftedNode) // 返回被删除的节点对象,或
|
|
403
|
+
console.log(shiftedNode) // 返回被删除的节点对象,或 null
|
|
404
|
+
|
|
405
|
+
// 尝试删除不存在的节点下的子节点
|
|
406
|
+
const shiftFailed = t.shiftTree(treeData, 999)
|
|
407
|
+
console.log(shiftFailed) // null
|
|
398
408
|
```
|
|
399
409
|
|
|
400
410
|
### removeTree
|
|
@@ -409,23 +419,138 @@ console.log(removeSuccess) // true 表示删除成功,false 表示未找到节
|
|
|
409
419
|
console.log(treeData) // 删除后的树结构
|
|
410
420
|
```
|
|
411
421
|
|
|
422
|
+
### concatTree
|
|
423
|
+
|
|
424
|
+
连接多个树结构数据,返回连接后的新树(深拷贝)。
|
|
425
|
+
|
|
426
|
+
```javascript
|
|
427
|
+
const tree1 = [
|
|
428
|
+
{ id: 1, name: 'node1' },
|
|
429
|
+
{ id: 2, name: 'node2' }
|
|
430
|
+
]
|
|
431
|
+
const tree2 = [
|
|
432
|
+
{ id: 3, name: 'node3' }
|
|
433
|
+
]
|
|
434
|
+
|
|
435
|
+
// 连接多个树
|
|
436
|
+
const result = t.concatTree(tree1, tree2)
|
|
437
|
+
console.log(result) // [{ id: 1, name: 'node1' }, { id: 2, name: 'node2' }, { id: 3, name: 'node3' }]
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
**参数说明:**
|
|
441
|
+
- `...trees`: 多个树结构数据数组(可变参数)
|
|
442
|
+
|
|
443
|
+
**注意事项:**
|
|
444
|
+
- 所有树都会被深拷贝,不会修改原树
|
|
445
|
+
- 支持连接任意数量的树结构
|
|
446
|
+
|
|
447
|
+
### sortTree
|
|
448
|
+
|
|
449
|
+
对树结构数据进行排序,递归排序所有层级。
|
|
450
|
+
|
|
451
|
+
```javascript
|
|
452
|
+
const tree = [
|
|
453
|
+
{ id: 3, name: 'node3' },
|
|
454
|
+
{ id: 1, name: 'node1' },
|
|
455
|
+
{ id: 2, name: 'node2' }
|
|
456
|
+
]
|
|
457
|
+
|
|
458
|
+
// 按 id 排序
|
|
459
|
+
const sorted = t.sortTree(tree, (a, b) => a.id - b.id)
|
|
460
|
+
console.log(sorted)
|
|
461
|
+
// [{ id: 1, name: 'node1' }, { id: 2, name: 'node2' }, { id: 3, name: 'node3' }]
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
**参数说明:**
|
|
465
|
+
- `tree`: 树结构数据
|
|
466
|
+
- `compareFn`: 比较函数,与 `Array.sort` 的 `compareFn` 相同(可选)
|
|
467
|
+
- `fieldNames`: 自定义字段名配置(可选)
|
|
468
|
+
|
|
469
|
+
**注意事项:**
|
|
470
|
+
- 递归排序所有层级的节点
|
|
471
|
+
- 返回排序后的新树(深拷贝),不修改原树
|
|
472
|
+
- 如果不提供 `compareFn`,将使用默认排序
|
|
473
|
+
|
|
474
|
+
### sliceTree
|
|
475
|
+
|
|
476
|
+
对树结构数据的根节点进行切片操作(类似数组的 `slice`)。
|
|
477
|
+
|
|
478
|
+
```javascript
|
|
479
|
+
const tree = [
|
|
480
|
+
{ id: 1, name: 'node1' },
|
|
481
|
+
{ id: 2, name: 'node2' },
|
|
482
|
+
{ id: 3, name: 'node3' }
|
|
483
|
+
]
|
|
484
|
+
|
|
485
|
+
// 切片:获取索引 1 到 3 的节点
|
|
486
|
+
const sliced = t.sliceTree(tree, 1, 3)
|
|
487
|
+
console.log(sliced) // [{ id: 2, name: 'node2' }, { id: 3, name: 'node3' }]
|
|
488
|
+
|
|
489
|
+
// 支持负数索引
|
|
490
|
+
const lastTwo = t.sliceTree(tree, -2)
|
|
491
|
+
console.log(lastTwo) // [{ id: 2, name: 'node2' }, { id: 3, name: 'node3' }]
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
**参数说明:**
|
|
495
|
+
- `tree`: 树结构数据
|
|
496
|
+
- `start`: 起始索引(包含),可选
|
|
497
|
+
- `end`: 结束索引(不包含),可选
|
|
498
|
+
- `fieldNames`: 自定义字段名配置(可选)
|
|
499
|
+
|
|
500
|
+
**注意事项:**
|
|
501
|
+
- 仅对根节点进行切片,不递归处理子节点
|
|
502
|
+
- 返回切片后的新树(深拷贝),不修改原树
|
|
503
|
+
- 支持负数索引(从末尾开始计算)
|
|
504
|
+
- 子节点结构会被完整保留
|
|
505
|
+
|
|
412
506
|
### dedupTree
|
|
413
507
|
|
|
414
|
-
|
|
508
|
+
树结构对象数组去重方法,根据指定的键去除重复节点。保留第一次出现的节点。支持单字段、多字段联合去重和自定义函数。
|
|
509
|
+
|
|
510
|
+
**参数说明:**
|
|
511
|
+
- `tree`: 树结构数据
|
|
512
|
+
- `dedupKey`: 用于去重的键名,支持三种类型:
|
|
513
|
+
- `string`: 单字段去重(如 `'id'`)
|
|
514
|
+
- `string[]`: 多字段联合去重(如 `['id', 'type']`)
|
|
515
|
+
- `(node: TreeNode) => any`: 自定义函数,返回用于去重的值
|
|
516
|
+
- `fieldNames`: 自定义字段名配置(可选)
|
|
415
517
|
|
|
416
518
|
```javascript
|
|
417
|
-
//
|
|
519
|
+
// 方式1:单字段去重(原有用法)
|
|
418
520
|
const uniqueTreeData = t.dedupTree(treeData, 'id')
|
|
419
521
|
console.log(uniqueTreeData) // 返回去重后的树结构数据
|
|
420
522
|
|
|
421
|
-
//
|
|
422
|
-
const
|
|
423
|
-
|
|
523
|
+
// 方式2:多字段联合去重(新功能)
|
|
524
|
+
const tree = [
|
|
525
|
+
{
|
|
526
|
+
id: 1,
|
|
527
|
+
children: [
|
|
528
|
+
{ id: 2, type: 'A', name: 'node1' },
|
|
529
|
+
{ id: 2, type: 'B', name: 'node2' }, // 保留(id相同但type不同)
|
|
530
|
+
{ id: 2, type: 'A', name: 'node3' }, // 去重(id和type都相同)
|
|
531
|
+
]
|
|
532
|
+
}
|
|
533
|
+
]
|
|
534
|
+
const uniqueByMultiFields = t.dedupTree(tree, ['id', 'type'])
|
|
535
|
+
// 结果:保留 node1 和 node2,node3 被去重
|
|
536
|
+
|
|
537
|
+
// 方式3:自定义函数去重
|
|
538
|
+
const uniqueByCustom = t.dedupTree(treeData, (node) => node.code)
|
|
539
|
+
// 或更复杂的逻辑
|
|
540
|
+
const uniqueByComplex = t.dedupTree(treeData, (node) => `${node.id}-${node.type}`)
|
|
424
541
|
```
|
|
425
542
|
|
|
543
|
+
**注意事项:**
|
|
544
|
+
- 如果 dedupKey 值为 `undefined` 或 `null`,节点不会被去重(会全部保留)
|
|
545
|
+
- 多字段联合去重使用字段值的组合来判断重复
|
|
546
|
+
- 递归处理所有层级的子节点
|
|
547
|
+
- **性能优化**:多字段联合去重已优化,使用高效的分隔符连接方式替代 JSON.stringify,提升性能
|
|
548
|
+
|
|
426
549
|
---
|
|
427
550
|
|
|
428
|
-
##
|
|
551
|
+
## 格式转换方法
|
|
552
|
+
|
|
553
|
+
在不同数据格式之间转换的方法(数组、Map、对象等格式转换)。
|
|
429
554
|
|
|
430
555
|
### convertToArrayTree
|
|
431
556
|
|
|
@@ -699,7 +824,169 @@ console.log(treeFromRecord) // 正确转换为树结构
|
|
|
699
824
|
|
|
700
825
|
---
|
|
701
826
|
|
|
702
|
-
##
|
|
827
|
+
## 克隆复制方法
|
|
828
|
+
|
|
829
|
+
复制树结构数据的方法(深拷贝、浅拷贝、子树拷贝等)。
|
|
830
|
+
|
|
831
|
+
### cloneTree
|
|
832
|
+
|
|
833
|
+
深拷贝树结构数据,返回完全独立的副本,不修改原树。
|
|
834
|
+
|
|
835
|
+
```javascript
|
|
836
|
+
const original = [
|
|
837
|
+
{ id: 1, name: 'node1', children: [{ id: 2, name: 'node2' }] }
|
|
838
|
+
]
|
|
839
|
+
|
|
840
|
+
// 深拷贝
|
|
841
|
+
const cloned = t.cloneTree(original)
|
|
842
|
+
|
|
843
|
+
// 修改克隆的树不会影响原树
|
|
844
|
+
cloned[0].name = 'modified'
|
|
845
|
+
console.log(original[0].name) // 'node1'
|
|
846
|
+
console.log(cloned[0].name) // 'modified'
|
|
847
|
+
```
|
|
848
|
+
|
|
849
|
+
**参数说明:**
|
|
850
|
+
- `tree`: 树结构数据
|
|
851
|
+
- `fieldNames`: 自定义字段名配置(可选)
|
|
852
|
+
|
|
853
|
+
**注意事项:**
|
|
854
|
+
- 递归深拷贝所有层级的节点和子节点
|
|
855
|
+
- 返回的树与原树完全独立,修改不会相互影响
|
|
856
|
+
- 支持自定义字段名配置
|
|
857
|
+
|
|
858
|
+
### shallowCloneTree
|
|
859
|
+
|
|
860
|
+
浅拷贝树结构数据(只拷贝第一层,子节点共享引用)。性能比深拷贝更好,适合只需要拷贝顶层结构的场景。
|
|
861
|
+
|
|
862
|
+
```javascript
|
|
863
|
+
const original = [
|
|
864
|
+
{ id: 1, name: 'node1', children: [{ id: 2, name: 'node2' }] }
|
|
865
|
+
]
|
|
866
|
+
|
|
867
|
+
// 浅拷贝
|
|
868
|
+
const cloned = t.shallowCloneTree(original)
|
|
869
|
+
|
|
870
|
+
// 修改第一层不会影响原树
|
|
871
|
+
cloned[0].name = 'modified'
|
|
872
|
+
console.log(original[0].name) // 'node1'
|
|
873
|
+
|
|
874
|
+
// 但子节点共享引用,修改子节点会影响原树
|
|
875
|
+
cloned[0].children[0].name = 'changed'
|
|
876
|
+
console.log(original[0].children[0].name) // 'changed'
|
|
877
|
+
```
|
|
878
|
+
|
|
879
|
+
**参数说明:**
|
|
880
|
+
- `tree`: 树结构数据
|
|
881
|
+
- `fieldNames`: 自定义字段名配置(可选)
|
|
882
|
+
|
|
883
|
+
**注意事项:**
|
|
884
|
+
- 只拷贝第一层节点,子节点保持引用共享
|
|
885
|
+
- 性能比深拷贝更好,适合只需要顶层独立的场景
|
|
886
|
+
- 修改子节点会影响原树
|
|
887
|
+
|
|
888
|
+
### cloneSubtree
|
|
889
|
+
|
|
890
|
+
从指定节点开始拷贝子树。返回包含目标节点及其所有子节点的深拷贝。支持按任意字段查找节点。
|
|
891
|
+
|
|
892
|
+
```javascript
|
|
893
|
+
const tree = [
|
|
894
|
+
{
|
|
895
|
+
id: 1,
|
|
896
|
+
name: 'root',
|
|
897
|
+
children: [
|
|
898
|
+
{ id: 2, name: 'sub1', children: [{ id: 4, name: 'sub1-1' }] },
|
|
899
|
+
{ id: 3, name: 'sub2' }
|
|
900
|
+
]
|
|
901
|
+
}
|
|
902
|
+
]
|
|
903
|
+
|
|
904
|
+
// 按 id 字段查找
|
|
905
|
+
const subtree1 = t.cloneSubtree(tree, { id: 2 })
|
|
906
|
+
console.log(subtree1)
|
|
907
|
+
// [{ id: 2, name: 'sub1', children: [{ id: 4, name: 'sub1-1' }] }]
|
|
908
|
+
|
|
909
|
+
// 按 name 字段查找
|
|
910
|
+
const subtree2 = t.cloneSubtree(tree, { name: 'sub1' })
|
|
911
|
+
console.log(subtree2)
|
|
912
|
+
// [{ id: 2, name: 'sub1', children: [{ id: 4, name: 'sub1-1' }] }]
|
|
913
|
+
|
|
914
|
+
// 按其他字段查找(如 code)
|
|
915
|
+
const treeWithCode = [
|
|
916
|
+
{
|
|
917
|
+
id: 1,
|
|
918
|
+
code: 'A001',
|
|
919
|
+
children: [
|
|
920
|
+
{ id: 2, code: 'B001', children: [{ id: 4, code: 'C001' }] }
|
|
921
|
+
]
|
|
922
|
+
}
|
|
923
|
+
]
|
|
924
|
+
const subtree3 = t.cloneSubtree(treeWithCode, { code: 'B001' })
|
|
925
|
+
console.log(subtree3)
|
|
926
|
+
// [{ id: 2, code: 'B001', children: [{ id: 4, code: 'C001' }] }]
|
|
927
|
+
|
|
928
|
+
// 支持自定义 children 字段名
|
|
929
|
+
const customTree = [
|
|
930
|
+
{ nodeId: 1, subNodes: [{ nodeId: 2 }] }
|
|
931
|
+
]
|
|
932
|
+
const subtree4 = t.cloneSubtree(customTree, { nodeId: 2 }, { children: 'subNodes', id: 'nodeId' })
|
|
933
|
+
console.log(subtree4)
|
|
934
|
+
// [{ nodeId: 2 }]
|
|
935
|
+
|
|
936
|
+
// 修改拷贝的子树不会影响原树
|
|
937
|
+
subtree1[0].name = 'modified'
|
|
938
|
+
console.log(tree[0].children[0].name) // 'sub1'
|
|
939
|
+
```
|
|
940
|
+
|
|
941
|
+
**参数说明:**
|
|
942
|
+
- `tree`: 树结构数据
|
|
943
|
+
- `target`: 目标节点对象,例如 `{ id: 1 }` 或 `{ name: 'sub1' }` 或 `{ code: 'B001' }`,对象只能包含一个字段
|
|
944
|
+
- `fieldNames`: 自定义字段名配置(可选,用于自定义 `children` 字段名,查找字段由 `target` 对象的键名决定)
|
|
945
|
+
|
|
946
|
+
**注意事项:**
|
|
947
|
+
- 返回包含目标节点的子树(深拷贝)
|
|
948
|
+
- 如果未找到目标节点,返回空数组
|
|
949
|
+
- 递归深拷贝所有子节点
|
|
950
|
+
- 必须传入对象形式,查找字段由对象的键名决定(如 `{ id: 1 }` 表示按 `id` 字段查找,`{ name: 'xxx' }` 表示按 `name` 字段查找)
|
|
951
|
+
- `fieldNames` 参数用于自定义 `children` 字段名,定义 `id` 不生效
|
|
952
|
+
|
|
953
|
+
### cloneWithTransform
|
|
954
|
+
|
|
955
|
+
拷贝树结构数据并对每个节点应用转换函数。适合在拷贝的同时修改节点数据。
|
|
956
|
+
|
|
957
|
+
```javascript
|
|
958
|
+
const tree = [
|
|
959
|
+
{ id: 1, name: 'node1', children: [{ id: 2, name: 'node2' }] }
|
|
960
|
+
]
|
|
961
|
+
|
|
962
|
+
// 拷贝并添加 label 字段
|
|
963
|
+
const cloned = t.cloneWithTransform(tree, (node) => ({
|
|
964
|
+
...node,
|
|
965
|
+
label: node.name,
|
|
966
|
+
processed: true
|
|
967
|
+
}))
|
|
968
|
+
|
|
969
|
+
console.log(cloned[0].label) // 'node1'
|
|
970
|
+
console.log(cloned[0].processed) // true
|
|
971
|
+
console.log(cloned[0].children[0].label) // 'node2'
|
|
972
|
+
console.log(tree[0].label) // undefined(原树未修改)
|
|
973
|
+
```
|
|
974
|
+
|
|
975
|
+
**参数说明:**
|
|
976
|
+
- `tree`: 树结构数据
|
|
977
|
+
- `transform`: 转换函数,接收节点并返回转换后的节点
|
|
978
|
+
- `fieldNames`: 自定义字段名配置(可选)
|
|
979
|
+
|
|
980
|
+
**注意事项:**
|
|
981
|
+
- 递归转换所有层级的节点
|
|
982
|
+
- 返回转换后的树(深拷贝),不修改原树
|
|
983
|
+
- 转换函数应该返回新的节点对象
|
|
984
|
+
|
|
985
|
+
---
|
|
986
|
+
|
|
987
|
+
## 关系查询方法
|
|
988
|
+
|
|
989
|
+
获取节点之间关系信息的方法(父子关系、兄弟关系、深度等)。
|
|
703
990
|
|
|
704
991
|
### getParentTree
|
|
705
992
|
|
|
@@ -850,7 +1137,9 @@ console.log(depth) // 2
|
|
|
850
1137
|
|
|
851
1138
|
---
|
|
852
1139
|
|
|
853
|
-
##
|
|
1140
|
+
## 数据验证方法
|
|
1141
|
+
|
|
1142
|
+
验证树结构数据有效性和节点类型的方法。
|
|
854
1143
|
|
|
855
1144
|
### isLeafNode
|
|
856
1145
|
|
|
@@ -902,6 +1191,8 @@ console.log(t.isLeafNode(customNode, fieldNames)) // true
|
|
|
902
1191
|
|
|
903
1192
|
检查节点是否是根节点(没有父节点)。根节点是树结构数据数组中的顶层节点。
|
|
904
1193
|
|
|
1194
|
+
**性能优化**:已优化为单次遍历,避免重复遍历树结构。
|
|
1195
|
+
|
|
905
1196
|
```javascript
|
|
906
1197
|
// 检查根节点
|
|
907
1198
|
const treeData = [
|
|
@@ -1249,6 +1540,435 @@ console.log(t.isSafeTreeDepth(customTree, 2, fieldNames)) // false
|
|
|
1249
1540
|
- 防止递归调用栈溢出
|
|
1250
1541
|
- 性能优化,避免处理过深的树结构
|
|
1251
1542
|
|
|
1543
|
+
---
|
|
1544
|
+
|
|
1545
|
+
## 聚合分析方法
|
|
1546
|
+
|
|
1547
|
+
对树结构数据进行聚合、统计和分析的方法。
|
|
1548
|
+
|
|
1549
|
+
### reduceTree
|
|
1550
|
+
|
|
1551
|
+
对树结构数据进行归约操作,遍历所有节点并累积结果。
|
|
1552
|
+
|
|
1553
|
+
```javascript
|
|
1554
|
+
const tree = [
|
|
1555
|
+
{ id: 1, value: 10 },
|
|
1556
|
+
{ id: 2, value: 20, children: [{ id: 3, value: 30 }] }
|
|
1557
|
+
]
|
|
1558
|
+
|
|
1559
|
+
// 计算所有节点值的总和
|
|
1560
|
+
const sum = t.reduceTree(tree, (acc, node) => acc + (node.value || 0), 0)
|
|
1561
|
+
console.log(sum) // 60
|
|
1562
|
+
|
|
1563
|
+
// 收集所有节点ID
|
|
1564
|
+
const ids = t.reduceTree(tree, (ids, node) => {
|
|
1565
|
+
ids.push(node.id)
|
|
1566
|
+
return ids
|
|
1567
|
+
}, [])
|
|
1568
|
+
console.log(ids) // [1, 2, 3]
|
|
1569
|
+
```
|
|
1570
|
+
|
|
1571
|
+
**参数说明:**
|
|
1572
|
+
- `tree`: 树结构数据
|
|
1573
|
+
- `reducer`: 归约函数,接收累加值和当前节点,返回新的累加值
|
|
1574
|
+
- `initialValue`: 初始值
|
|
1575
|
+
- `fieldNames`: 自定义字段名配置(可选)
|
|
1576
|
+
|
|
1577
|
+
**注意事项:**
|
|
1578
|
+
- 按深度优先顺序遍历所有节点
|
|
1579
|
+
- 可以用于实现各种聚合操作
|
|
1580
|
+
|
|
1581
|
+
---
|
|
1582
|
+
|
|
1583
|
+
### aggregateTree
|
|
1584
|
+
|
|
1585
|
+
按分组聚合树结构数据,支持多种聚合操作(求和、平均值、最大值、最小值、计数)。
|
|
1586
|
+
|
|
1587
|
+
```javascript
|
|
1588
|
+
const tree = [
|
|
1589
|
+
{ id: 1, category: 'A', value: 10, score: 80 },
|
|
1590
|
+
{ id: 2, category: 'A', value: 20, score: 90 },
|
|
1591
|
+
{ id: 3, category: 'B', value: 30, score: 70, children: [{ id: 4, category: 'B', value: 40, score: 85 }] }
|
|
1592
|
+
]
|
|
1593
|
+
|
|
1594
|
+
// 按 category 分组聚合
|
|
1595
|
+
const result = t.aggregateTree(tree, {
|
|
1596
|
+
groupBy: node => node.category,
|
|
1597
|
+
aggregations: {
|
|
1598
|
+
totalValue: { operation: 'sum', field: 'value' },
|
|
1599
|
+
avgScore: { operation: 'avg', field: 'score' },
|
|
1600
|
+
maxValue: { operation: 'max', field: 'value' },
|
|
1601
|
+
count: { operation: 'count' }
|
|
1602
|
+
}
|
|
1603
|
+
})
|
|
1604
|
+
|
|
1605
|
+
console.log(result)
|
|
1606
|
+
// {
|
|
1607
|
+
// 'A': { totalValue: 30, avgScore: 85, maxValue: 20, count: 2 },
|
|
1608
|
+
// 'B': { totalValue: 70, avgScore: 77.5, maxValue: 40, count: 2 }
|
|
1609
|
+
// }
|
|
1610
|
+
```
|
|
1611
|
+
|
|
1612
|
+
**参数说明:**
|
|
1613
|
+
- `tree`: 树结构数据
|
|
1614
|
+
- `options`: 聚合选项
|
|
1615
|
+
- `groupBy`: 分组函数,接收节点并返回分组键
|
|
1616
|
+
- `aggregations`: 聚合配置对象,键为结果字段名,值为聚合配置
|
|
1617
|
+
- `operation`: 聚合操作类型('sum' | 'avg' | 'max' | 'min' | 'count')
|
|
1618
|
+
- `field`: 要聚合的字段名(count 操作不需要)
|
|
1619
|
+
- `fieldNames`: 自定义字段名配置(可选)
|
|
1620
|
+
|
|
1621
|
+
**注意事项:**
|
|
1622
|
+
- 支持多种聚合操作同时进行
|
|
1623
|
+
- 递归处理所有层级的节点
|
|
1624
|
+
- count 操作统计节点数量,不需要 field 参数
|
|
1625
|
+
|
|
1626
|
+
---
|
|
1627
|
+
|
|
1628
|
+
### groupTree
|
|
1629
|
+
|
|
1630
|
+
按字段分组树结构数据,返回按字段值分组的节点数组。
|
|
1631
|
+
|
|
1632
|
+
```javascript
|
|
1633
|
+
const tree = [
|
|
1634
|
+
{ id: 1, category: 'A' },
|
|
1635
|
+
{ id: 2, category: 'A' },
|
|
1636
|
+
{ id: 3, category: 'B', children: [{ id: 4, category: 'B' }] }
|
|
1637
|
+
]
|
|
1638
|
+
|
|
1639
|
+
// 按 category 字段分组
|
|
1640
|
+
const grouped = t.groupTree(tree, 'category')
|
|
1641
|
+
console.log(grouped)
|
|
1642
|
+
// {
|
|
1643
|
+
// 'A': [{ id: 1, category: 'A' }, { id: 2, category: 'A' }],
|
|
1644
|
+
// 'B': [{ id: 3, category: 'B' }, { id: 4, category: 'B' }]
|
|
1645
|
+
// }
|
|
1646
|
+
```
|
|
1647
|
+
|
|
1648
|
+
**参数说明:**
|
|
1649
|
+
- `tree`: 树结构数据
|
|
1650
|
+
- `field`: 分组字段名
|
|
1651
|
+
- `fieldNames`: 自定义字段名配置(可选)
|
|
1652
|
+
|
|
1653
|
+
**注意事项:**
|
|
1654
|
+
- 返回的节点是原节点的引用,不是深拷贝
|
|
1655
|
+
- 递归处理所有层级的节点
|
|
1656
|
+
|
|
1657
|
+
---
|
|
1658
|
+
|
|
1659
|
+
### groupByTree
|
|
1660
|
+
|
|
1661
|
+
按条件分组树结构数据,使用自定义函数确定分组键。
|
|
1662
|
+
|
|
1663
|
+
```javascript
|
|
1664
|
+
const tree = [
|
|
1665
|
+
{ id: 1, value: 10 },
|
|
1666
|
+
{ id: 2, value: 20 },
|
|
1667
|
+
{ id: 3, value: 10, children: [{ id: 4, value: 30 }] }
|
|
1668
|
+
]
|
|
1669
|
+
|
|
1670
|
+
// 按 value 是否大于等于 20 分组
|
|
1671
|
+
const grouped = t.groupByTree(tree, node => node.value >= 20 ? 'high' : 'low')
|
|
1672
|
+
console.log(grouped)
|
|
1673
|
+
// {
|
|
1674
|
+
// 'low': [{ id: 1, value: 10 }, { id: 3, value: 10 }],
|
|
1675
|
+
// 'high': [{ id: 2, value: 20 }, { id: 4, value: 30 }]
|
|
1676
|
+
// }
|
|
1677
|
+
```
|
|
1678
|
+
|
|
1679
|
+
**参数说明:**
|
|
1680
|
+
- `tree`: 树结构数据
|
|
1681
|
+
- `groupFn`: 分组函数,接收节点并返回分组键
|
|
1682
|
+
- `fieldNames`: 自定义字段名配置(可选)
|
|
1683
|
+
|
|
1684
|
+
**注意事项:**
|
|
1685
|
+
- 分组键会被转换为字符串
|
|
1686
|
+
- 返回的节点是原节点的引用,不是深拷贝
|
|
1687
|
+
|
|
1688
|
+
---
|
|
1689
|
+
|
|
1690
|
+
### sumTree
|
|
1691
|
+
|
|
1692
|
+
计算树结构数据中某个字段的总和。
|
|
1693
|
+
|
|
1694
|
+
```javascript
|
|
1695
|
+
const tree = [
|
|
1696
|
+
{ id: 1, value: 10 },
|
|
1697
|
+
{ id: 2, value: 20, children: [{ id: 3, value: 30 }] }
|
|
1698
|
+
]
|
|
1699
|
+
|
|
1700
|
+
// 计算 value 字段的总和
|
|
1701
|
+
const total = t.sumTree(tree, 'value')
|
|
1702
|
+
console.log(total) // 60
|
|
1703
|
+
```
|
|
1704
|
+
|
|
1705
|
+
**参数说明:**
|
|
1706
|
+
- `tree`: 树结构数据
|
|
1707
|
+
- `field`: 字段名
|
|
1708
|
+
- `fieldNames`: 自定义字段名配置(可选)
|
|
1709
|
+
|
|
1710
|
+
**注意事项:**
|
|
1711
|
+
- 缺失或 null/undefined 的值会被视为 0
|
|
1712
|
+
- 递归处理所有层级的节点
|
|
1713
|
+
|
|
1714
|
+
---
|
|
1715
|
+
|
|
1716
|
+
### avgTree
|
|
1717
|
+
|
|
1718
|
+
计算树结构数据中某个字段的平均值。
|
|
1719
|
+
|
|
1720
|
+
```javascript
|
|
1721
|
+
const tree = [
|
|
1722
|
+
{ id: 1, value: 10 },
|
|
1723
|
+
{ id: 2, value: 20 },
|
|
1724
|
+
{ id: 3, value: 30 }
|
|
1725
|
+
]
|
|
1726
|
+
|
|
1727
|
+
// 计算 value 字段的平均值
|
|
1728
|
+
const average = t.avgTree(tree, 'value')
|
|
1729
|
+
console.log(average) // 20
|
|
1730
|
+
```
|
|
1731
|
+
|
|
1732
|
+
**参数说明:**
|
|
1733
|
+
- `tree`: 树结构数据
|
|
1734
|
+
- `field`: 字段名
|
|
1735
|
+
- `fieldNames`: 自定义字段名配置(可选)
|
|
1736
|
+
|
|
1737
|
+
**注意事项:**
|
|
1738
|
+
- 忽略 null 和 undefined 值
|
|
1739
|
+
- 如果所有值都是 null/undefined,返回 0
|
|
1740
|
+
|
|
1741
|
+
---
|
|
1742
|
+
|
|
1743
|
+
### maxTree
|
|
1744
|
+
|
|
1745
|
+
获取树结构数据中某个字段的最大值。
|
|
1746
|
+
|
|
1747
|
+
```javascript
|
|
1748
|
+
const tree = [
|
|
1749
|
+
{ id: 1, value: 10 },
|
|
1750
|
+
{ id: 2, value: 30 },
|
|
1751
|
+
{ id: 3, value: 20 }
|
|
1752
|
+
]
|
|
1753
|
+
|
|
1754
|
+
// 获取 value 字段的最大值
|
|
1755
|
+
const max = t.maxTree(tree, 'value')
|
|
1756
|
+
console.log(max) // 30
|
|
1757
|
+
```
|
|
1758
|
+
|
|
1759
|
+
**参数说明:**
|
|
1760
|
+
- `tree`: 树结构数据
|
|
1761
|
+
- `field`: 字段名
|
|
1762
|
+
- `fieldNames`: 自定义字段名配置(可选)
|
|
1763
|
+
|
|
1764
|
+
**注意事项:**
|
|
1765
|
+
- 只处理数字类型的值
|
|
1766
|
+
- 如果树为空或没有有效值,返回 null
|
|
1767
|
+
|
|
1768
|
+
---
|
|
1769
|
+
|
|
1770
|
+
### minTree
|
|
1771
|
+
|
|
1772
|
+
获取树结构数据中某个字段的最小值。
|
|
1773
|
+
|
|
1774
|
+
```javascript
|
|
1775
|
+
const tree = [
|
|
1776
|
+
{ id: 1, value: 30 },
|
|
1777
|
+
{ id: 2, value: 10 },
|
|
1778
|
+
{ id: 3, value: 20 }
|
|
1779
|
+
]
|
|
1780
|
+
|
|
1781
|
+
// 获取 value 字段的最小值
|
|
1782
|
+
const min = t.minTree(tree, 'value')
|
|
1783
|
+
console.log(min) // 10
|
|
1784
|
+
```
|
|
1785
|
+
|
|
1786
|
+
**参数说明:**
|
|
1787
|
+
- `tree`: 树结构数据
|
|
1788
|
+
- `field`: 字段名
|
|
1789
|
+
- `fieldNames`: 自定义字段名配置(可选)
|
|
1790
|
+
|
|
1791
|
+
**注意事项:**
|
|
1792
|
+
- 只处理数字类型的值
|
|
1793
|
+
- 如果树为空或没有有效值,返回 null
|
|
1794
|
+
|
|
1795
|
+
---
|
|
1796
|
+
|
|
1797
|
+
### countTree
|
|
1798
|
+
|
|
1799
|
+
统计树结构数据中满足条件的节点数量。
|
|
1800
|
+
|
|
1801
|
+
```javascript
|
|
1802
|
+
const tree = [
|
|
1803
|
+
{ id: 1, value: 10 },
|
|
1804
|
+
{ id: 2, value: 20 },
|
|
1805
|
+
{ id: 3, value: 10, children: [{ id: 4, value: 30 }] }
|
|
1806
|
+
]
|
|
1807
|
+
|
|
1808
|
+
// 统计所有节点
|
|
1809
|
+
const total = t.countTree(tree)
|
|
1810
|
+
console.log(total) // 4
|
|
1811
|
+
|
|
1812
|
+
// 统计满足条件的节点
|
|
1813
|
+
const count = t.countTree(tree, node => node.value === 10)
|
|
1814
|
+
console.log(count) // 2
|
|
1815
|
+
```
|
|
1816
|
+
|
|
1817
|
+
**参数说明:**
|
|
1818
|
+
- `tree`: 树结构数据
|
|
1819
|
+
- `conditionFn`: 统计条件函数(可选),不传则统计所有节点
|
|
1820
|
+
- `fieldNames`: 自定义字段名配置(可选)
|
|
1821
|
+
|
|
1822
|
+
**注意事项:**
|
|
1823
|
+
- 不传条件函数时统计所有节点
|
|
1824
|
+
- 递归处理所有层级的节点
|
|
1825
|
+
|
|
1826
|
+
---
|
|
1827
|
+
|
|
1828
|
+
### getTreeStats
|
|
1829
|
+
|
|
1830
|
+
获取树结构数据的综合统计信息。
|
|
1831
|
+
|
|
1832
|
+
```javascript
|
|
1833
|
+
const tree = [
|
|
1834
|
+
{ id: 1, children: [{ id: 2 }, { id: 3, children: [{ id: 4 }] }] }
|
|
1835
|
+
]
|
|
1836
|
+
|
|
1837
|
+
// 获取统计信息
|
|
1838
|
+
const stats = t.getTreeStats(tree)
|
|
1839
|
+
console.log(stats)
|
|
1840
|
+
// {
|
|
1841
|
+
// totalNodes: 4, // 总节点数
|
|
1842
|
+
// leafNodes: 2, // 叶子节点数
|
|
1843
|
+
// maxDepth: 3, // 最大深度
|
|
1844
|
+
// minDepth: 1, // 最小深度
|
|
1845
|
+
// avgDepth: 2, // 平均深度
|
|
1846
|
+
// levels: 3 // 层级数(等于最大深度)
|
|
1847
|
+
// }
|
|
1848
|
+
```
|
|
1849
|
+
|
|
1850
|
+
**参数说明:**
|
|
1851
|
+
- `tree`: 树结构数据
|
|
1852
|
+
- `fieldNames`: 自定义字段名配置(可选)
|
|
1853
|
+
|
|
1854
|
+
**注意事项:**
|
|
1855
|
+
- 返回完整的统计信息对象
|
|
1856
|
+
- 空树返回所有值为 0 的统计信息
|
|
1857
|
+
|
|
1858
|
+
---
|
|
1859
|
+
|
|
1860
|
+
### analyzeTree
|
|
1861
|
+
|
|
1862
|
+
全面分析树结构数据,提供详细的统计信息、分布情况、平衡性分析等。
|
|
1863
|
+
|
|
1864
|
+
```javascript
|
|
1865
|
+
const tree = [
|
|
1866
|
+
{ id: 1, children: [{ id: 2 }, { id: 3, children: [{ id: 4 }] }] }
|
|
1867
|
+
]
|
|
1868
|
+
|
|
1869
|
+
// 全面分析树结构
|
|
1870
|
+
const analysis = t.analyzeTree(tree)
|
|
1871
|
+
console.log(analysis)
|
|
1872
|
+
// {
|
|
1873
|
+
// // 基础统计
|
|
1874
|
+
// totalNodes: 4, // 总节点数
|
|
1875
|
+
// leafNodes: 2, // 叶子节点数
|
|
1876
|
+
// internalNodes: 2, // 内部节点数
|
|
1877
|
+
// maxDepth: 3, // 最大深度
|
|
1878
|
+
// minDepth: 1, // 最小深度
|
|
1879
|
+
// avgDepth: 2, // 平均深度
|
|
1880
|
+
// levels: 3, // 层级数
|
|
1881
|
+
//
|
|
1882
|
+
// // 层级分析
|
|
1883
|
+
// byLevel: { 0: 1, 1: 2, 2: 1 }, // 按层级统计节点数
|
|
1884
|
+
// maxWidth: 2, // 最大宽度(单层最多节点数)
|
|
1885
|
+
// avgWidth: 1.33, // 平均宽度
|
|
1886
|
+
// widthByLevel: { 0: 1, 1: 2, 2: 1 }, // 每层宽度
|
|
1887
|
+
//
|
|
1888
|
+
// // 分支因子分析
|
|
1889
|
+
// avgBranchingFactor: 1.5, // 平均分支因子(平均子节点数)
|
|
1890
|
+
// maxBranchingFactor: 2, // 最大分支因子
|
|
1891
|
+
// minBranchingFactor: 1, // 最小分支因子
|
|
1892
|
+
// branchingFactorDistribution: { 1: 1, 2: 1 }, // 分支因子分布
|
|
1893
|
+
//
|
|
1894
|
+
// // 深度分布
|
|
1895
|
+
// depthDistribution: { 1: 1, 2: 2, 3: 1 }, // 按深度统计节点数
|
|
1896
|
+
//
|
|
1897
|
+
// // 平衡性分析
|
|
1898
|
+
// depthVariance: 0.5, // 深度方差(越小越平衡)
|
|
1899
|
+
// isBalanced: true, // 是否平衡
|
|
1900
|
+
// balanceRatio: 0.33, // 平衡比率(minDepth/maxDepth)
|
|
1901
|
+
//
|
|
1902
|
+
// // 路径分析
|
|
1903
|
+
// avgPathLength: 2.25, // 平均路径长度
|
|
1904
|
+
// maxPathLength: 3, // 最大路径长度
|
|
1905
|
+
// minPathLength: 1, // 最小路径长度
|
|
1906
|
+
//
|
|
1907
|
+
// // 叶子节点分析
|
|
1908
|
+
// leafNodeRatio: 0.5, // 叶子节点比例
|
|
1909
|
+
// leafNodesByLevel: { 2: 1, 3: 1 } // 每层叶子节点数
|
|
1910
|
+
// }
|
|
1911
|
+
```
|
|
1912
|
+
|
|
1913
|
+
**参数说明:**
|
|
1914
|
+
- `tree`: 树结构数据
|
|
1915
|
+
- `options`: 分析选项(可选),可指定需要计算的统计项,默认计算所有统计项
|
|
1916
|
+
- `includeBasic`: 是否包含基础统计(totalNodes, leafNodes, internalNodes, maxDepth, minDepth, avgDepth, levels),默认 `true`
|
|
1917
|
+
- `includeLevelAnalysis`: 是否包含层级分析(byLevel, maxWidth, avgWidth, widthByLevel),默认 `true`
|
|
1918
|
+
- `includeBranchingFactor`: 是否包含分支因子分析(avgBranchingFactor, maxBranchingFactor, minBranchingFactor, branchingFactorDistribution),默认 `true`
|
|
1919
|
+
- `includeDepthDistribution`: 是否包含深度分布(depthDistribution),默认 `true`
|
|
1920
|
+
- `includeBalanceAnalysis`: 是否包含平衡性分析(depthVariance, isBalanced, balanceRatio),默认 `true`
|
|
1921
|
+
- `includePathAnalysis`: 是否包含路径分析(avgPathLength, maxPathLength, minPathLength),默认 `true`
|
|
1922
|
+
- `includeLeafAnalysis`: 是否包含叶子节点分析(leafNodeRatio, leafNodesByLevel),默认 `true`
|
|
1923
|
+
- `fieldNames`: 自定义字段名配置(可选)
|
|
1924
|
+
|
|
1925
|
+
```javascript
|
|
1926
|
+
// 只计算基础统计和分支因子(性能优化)
|
|
1927
|
+
const quickAnalysis = t.analyzeTree(tree, {
|
|
1928
|
+
includeBasic: true,
|
|
1929
|
+
includeBranchingFactor: true,
|
|
1930
|
+
includeLevelAnalysis: false,
|
|
1931
|
+
includeDepthDistribution: false,
|
|
1932
|
+
includeBalanceAnalysis: false,
|
|
1933
|
+
includePathAnalysis: false,
|
|
1934
|
+
includeLeafAnalysis: false,
|
|
1935
|
+
})
|
|
1936
|
+
console.log(quickAnalysis.totalNodes) // 4
|
|
1937
|
+
console.log(quickAnalysis.maxBranchingFactor) // 2
|
|
1938
|
+
console.log(quickAnalysis.byLevel) // {} (未计算)
|
|
1939
|
+
|
|
1940
|
+
// 只计算平衡性分析
|
|
1941
|
+
const balanceAnalysis = t.analyzeTree(tree, {
|
|
1942
|
+
includeBasic: true,
|
|
1943
|
+
includeBalanceAnalysis: true,
|
|
1944
|
+
includeLevelAnalysis: false,
|
|
1945
|
+
includeBranchingFactor: false,
|
|
1946
|
+
includeDepthDistribution: false,
|
|
1947
|
+
includePathAnalysis: false,
|
|
1948
|
+
includeLeafAnalysis: false,
|
|
1949
|
+
})
|
|
1950
|
+
console.log(balanceAnalysis.isBalanced) // true/false
|
|
1951
|
+
console.log(balanceAnalysis.depthVariance) // 0.5
|
|
1952
|
+
```
|
|
1953
|
+
|
|
1954
|
+
**返回的分析信息包括:**
|
|
1955
|
+
|
|
1956
|
+
1. **基础统计**:总节点数、叶子节点数、内部节点数、深度信息等
|
|
1957
|
+
2. **层级分析**:每层节点数、最大宽度、平均宽度等
|
|
1958
|
+
3. **分支因子分析**:平均/最大/最小分支因子、分支因子分布等
|
|
1959
|
+
4. **深度分布**:每个深度的节点数量
|
|
1960
|
+
5. **平衡性分析**:深度方差、是否平衡、平衡比率等
|
|
1961
|
+
6. **路径分析**:平均/最大/最小路径长度
|
|
1962
|
+
7. **叶子节点分析**:叶子节点比例、每层叶子节点数
|
|
1963
|
+
|
|
1964
|
+
**注意事项:**
|
|
1965
|
+
- 提供全面的树结构分析,适合用于性能优化、结构评估等场景
|
|
1966
|
+
- `isBalanced` 基于深度方差和深度范围判断,深度方差 < 2 且深度范围 ≤ 2 视为平衡
|
|
1967
|
+
- `balanceRatio` 接近 1 表示树更平衡
|
|
1968
|
+
- **性能优化**:通过 `options` 参数可以只计算需要的统计项,对于大型树结构可以显著提升性能
|
|
1969
|
+
|
|
1970
|
+
---
|
|
1971
|
+
|
|
1252
1972
|
## 自定义字段名
|
|
1253
1973
|
|
|
1254
1974
|
所有方法都支持自定义 children 和 id 的属性名,通过最后一个参数传入配置对象:
|
|
@@ -1269,21 +1989,20 @@ const foundNode2 = t.findTree(customTreeData, (node) => node.nodeId === 2, field
|
|
|
1269
1989
|
### 运行测试
|
|
1270
1990
|
|
|
1271
1991
|
```bash
|
|
1272
|
-
# 运行所有测试(自动打包后测试源码 + 打包文件,
|
|
1992
|
+
# 运行所有测试(自动打包后测试源码 + 打包文件,712 个测试用例)
|
|
1273
1993
|
npm test
|
|
1274
1994
|
|
|
1275
1995
|
# 运行所有测试(单次,不监听文件变化)
|
|
1276
1996
|
npm test -- --run
|
|
1277
1997
|
|
|
1278
|
-
# 仅测试源代码(
|
|
1998
|
+
# 仅测试源代码(447 个测试用例)
|
|
1279
1999
|
npm run test:src
|
|
1280
2000
|
|
|
1281
|
-
# 仅测试打包后的文件(
|
|
2001
|
+
# 仅测试打包后的文件(447 个测试用例,需要先运行 npm run build)
|
|
1282
2002
|
npm run test:dist
|
|
1283
2003
|
|
|
1284
2004
|
# 运行测试并生成覆盖率报告
|
|
1285
2005
|
npm run test:coverage
|
|
1286
|
-
```
|
|
1287
2006
|
|
|
1288
2007
|
## 开发
|
|
1289
2008
|
|