在写一个富文本编辑器,其中用到了带父子节点的双向链表,要把无顺序的节点树根据 prev_id ,next_id 处理成顺序的,而且有些节点是带 children 的,children 中的节点同其他节点,可无限嵌套,写了个递归一直报错,希望大佬指点指点,答案被采纳我 v 信转 120 给您(不在乎钱的也可以试一试,这十分考验算法实战能力)
raw_nodes 数据:
const raw_nodes = [
{
"type": "file",
"name": "工作目录二",
"icon": "",
"id": "dgacbecjhzbcufq13_rvmr_gjz98xo",
"module": "todo",
"pid": "kzoxuadlnqrtxeg43xugw2s0voutnj",
"prev_id": "pcwsejrnwzuwjpyve64ww68hxxt74r"
},
{
"type": "file",
"name": "日常",
"icon": "",
"id": "gpvwcojxffgijtw14xat7-ealc7w8l",
"module": "todo",
"pid": "",
"prev_id": "kzoxuadlnqrtxeg43xugw2s0voutnj"
},
{
"type": "dir",
"name": "工作",
"icon": "",
"id": "kzoxuadlnqrtxeg43xugw2s0voutnj",
"module": "todo",
"pid": "",
"next_id": "gpvwcojxffgijtw14xat7-ealc7w8l"
},
{
"type": "file",
"name": "工作目录一",
"icon": "",
"id": "pcwsejrnwzuwjpyve64ww68hxxt74r",
"module": "todo",
"pid": "kzoxuadlnqrtxeg43xugw2s0voutnj",
"next_id": "kzoxuadlnqrtxeg43xugw2s0voutnj"
}
]
tree 数据和 tree_map 由下面 class 中的函数可计算出来:
class 的一部分:
import { get, flatMap, last, initial, cloneDeep, find } from 'lodash-es'
type RawNode = {
id: string
pid?: string
prev_id?: string
next_id?: string
[key: string]: any
}
type RawNodes = Array<RawNode>
type TreeItem = RawNode & { children?: Tree }
type Tree = Array<TreeItem>
type TreeMap = Record<string, TreeItem>
export default class Index {
tree = [] as Tree
public init(raw_nodes: RawNodes) {
const raw_tree_map = this.setRawMap(raw_nodes)
const { tree, tree_map } = this.getTree(raw_nodes, raw_tree_map)
console.log(tree)
this.tree = this.sortTree(tree, tree_map)
}
private setRawMap(raw_nodes: RawNodes) {
const tree_map = {} as TreeMap
raw_nodes.map((item) => {
tree_map[item.id] = item
})
return tree_map
}
private getTree(raw_nodes: RawNodes, tree_map: TreeMap) {
const tree = [] as Tree
raw_nodes.forEach((item) => {
if (item.pid) {
if (!tree_map[item.pid].children) {
tree_map[item.pid].children = []
}
if (!tree_map[item.pid]?.children?.length) {
tree_map[item.pid].children = [item]
} else {
tree_map[item.pid].children.push(item)
}
} else {
tree.push(item)
}
})
return { tree, tree_map }
}
private sortTree(tree: Tree, tree_map: TreeMap) {
const target_tree = [] as Tree
const start_node = find(tree, (item) => !item.prev_id)
if (!start_node) return []
let current = start_node.id
while (current) {
const item = tree_map[current]
if (item?.children?.length) {
// 这里报错( RangeError: Maximum call stack size exceeded )
// item.children = this.sortTree(item.children, tree_map)
}
target_tree.push(item)
current = item.next_id
}
return target_tree
}
}
正确的情况应输出数据为:
const tree = [
{
"type": "dir",
"name": "工作",
"icon": "",
"id": "kzoxuadlnqrtxeg43xugw2s0voutnj",
"module": "todo",
"pid": "",
"next_id": "gpvwcojxffgijtw14xat7-ealc7w8l",
"children": [
{
"type": "file",
"name": "工作目录一",
"icon": "",
"id": "pcwsejrnwzuwjpyve64ww68hxxt74r",
"module": "todo",
"pid": "kzoxuadlnqrtxeg43xugw2s0voutnj",
"next_id": "kzoxuadlnqrtxeg43xugw2s0voutnj"
},
{
"type": "file",
"name": "工作目录二",
"icon": "",
"id": "dgacbecjhzbcufq13_rvmr_gjz98xo",
"module": "todo",
"pid": "kzoxuadlnqrtxeg43xugw2s0voutnj",
"prev_id": "pcwsejrnwzuwjpyve64ww68hxxt74r"
},
]
},
{
"type": "file",
"name": "日常",
"icon": "",
"id": "gpvwcojxffgijtw14xat7-ealc7w8l",
"module": "todo",
"pid": "",
"prev_id": "kzoxuadlnqrtxeg43xugw2s0voutnj"
},
]
哪位大佬指点迷津,小弟 v 您 60+60 ,祝您 66 大顺!
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.