-
Notifications
You must be signed in to change notification settings - Fork 0
/
deep.mjs
147 lines (145 loc) · 4.18 KB
/
deep.mjs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
import { arrayEach } from './array.mjs';
import { isArray, isFunction } from './type.mjs';
/**
* 深度遍历
* @param {DeepList} deepList
* @param {DeepEachIterator} iterator
* @param {boolean} breadthFist 是否广度优先
*/
const deepEach = (deepList, iterator, breadthFist = false) => {
const deepWalkers = [];
let returnFalse = false;
const iterate = (walker) => {
const { item, index, list, parent, level } = walker;
if (iterator(item, index, list, parent, level) === false) {
returnFalse = true;
return false;
}
};
const next = (walker, walk) => {
const { item, level } = walker;
const { children } = item;
if (isArray(children))
returnFalse = walk(children, level + 1, item) === false;
};
const walk = (deepList, level, parent) => {
if (returnFalse)
return false;
arrayEach(deepList, (item, index) => {
const walker = { item, index, list: deepList, parent, level };
// 广度优先
if (breadthFist) {
deepWalkers.push(walker);
}
// 深度优先
else {
iterate(walker);
if (returnFalse)
return false;
next(walker, walk);
}
});
if (breadthFist) {
let walker;
while ((walker = deepWalkers.shift())) {
iterate(walker);
if (returnFalse)
break;
next(walker, walk);
}
}
return !returnFalse;
};
walk(deepList, 1, null);
};
/**
* 深度替换
* @param {DeepList} deepList
* @param {DeepMapIterator} iterator
* @returns {DeepItem[]}
*/
const deepMap = (deepList, iterator) => {
const walk = (deepList, parent, level) => {
const list2 = [];
arrayEach(deepList, (val, index) => {
const { children } = val;
const data = iterator(val, index, deepList, parent, level);
if (isArray(children))
data.children = walk(children, data, level + 1);
list2.push(data);
});
return list2;
};
return walk(deepList, null, 1);
};
/**
* 展平
* @param {DeepList<I>} deepList
* @param {boolean} breadthFist
* @returns {I[]}
*/
const deepFlat = (deepList, breadthFist = false) => {
const list2 = [];
deepEach(deepList, (item, index, list, parent, level) => {
list2.push(item);
}, breadthFist);
return list2;
};
/**
* 深度查找
* @param {DeepList} deepList
* @param {DeepExpected} expected
* @returns {DeepFound | null}
*/
const deepFind = (deepList, expected) => {
let matcher;
if (isFunction(expected)) {
matcher = expected;
}
else {
matcher = (actural) => actural === expected;
}
let found = null;
const foundPath = [];
deepEach(deepList, (item, index, list, parent, level) => {
if (level > 1) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
foundPath[level - 2] = parent;
}
if (matcher(item, index, list, parent, level, foundPath)) {
let path = foundPath;
if (path.length > level - 1) {
path = path.slice(0, level - 1);
}
path.push(item);
found = { item, index, list, parent, level, path };
return false;
}
}, false);
return found;
};
/**
* 过滤替换
* @param {DeepList} deepList
* @param {DeepFilter} filter
* @returns {DeepList}
*/
const deepFilter = (deepList, filter) => {
const walk = (list1, parent, level) => {
const list2 = [];
list1.forEach((item, index) => {
const { children } = item;
const filtered = filter(item, index, list1, parent, level);
if (!filtered) {
return;
}
if (isArray(children))
item.children = walk(children, item, level + 1);
list2.push(item);
});
return list2;
};
return walk(deepList, null, 1);
};
export { deepEach, deepFilter, deepFind, deepFlat, deepMap };