我有一个 data.frame,其中一列代表节点路径,我想将其转换为一棵树。我有什么简单的功能可以做到这一点吗?
这是一个简单的例子:
data <- data.frame(
Name = c("A", "A1", "A2", "A1a", "A1b", "A2a", "A2b", "A2c"),
Path = c("1", "1,1", "1,2", "1,1,1", "1,1,2", "1,2,1", "1,2,2", "1,2,3")
)
我想转变为:
nodes <- list(
list(
text = "A",
li_attr = list(id = "1")
state = list(opened = TRUE),
children = list(
list(
text = "A1",
li_attr = list(id = "1,1")
state = list(opened = TRUE),
children = list(
list(
text = "A1a",
li_attr = list(id = "1,1,1")),
list(
text = "A1b",
li_attr = list(id = "1,1,2"))
)),
list(
text = "A2",
li_attr = list(id = "1,2")
state = list(opened = TRUE),
children = list(
list(
text = "A2a",
li_attr = list(id = "1,2,1")),
list(
text = "A2b",
li_attr = list(id = "1,2,2")),
list(
text = "A2c",
li_attr = list(id = "1,2,3"))
)
)
)
)
)
没有现有的功能可以完全满足您的要求。您必须编写一个递归函数来为您完成此操作:
f <- function(path, name, parent_node = NULL) {
nodes <- strsplit(path, ',')
parents <- match(unique(sapply(nodes, `[`, 1)), path)
lapply(parents, function(i) {
li <- list(Text = name[i],
li_attr = list(id = if(is.null(parent_node)) parents[i]
else paste(parent_node, parents[i], sep = ',')))
kids <- sapply(nodes, \(x) x[1] == parents[i])
if(length(kids) > 0) {
if(sum(kids) > 1) {
n <- which(kids & lengths(nodes) > 1)
li$children <-
f(sapply(nodes[n], \(x) paste0(x[-1], collapse = ',')), name[n],
parent_node = li$li_attr$id)
}
}
return(li)
})
}
我们这样称呼它:
result <- f(data$Path, data$Name)
结果如下所示:
list(
list(Text = "A",
li_attr = list(id = 1L),
children = list(
list(Text = "A1",
li_attr = list(id = "1,1"),
children = list(
list(Text = "A1a",
li_attr = list(id = "1,1,1")),
list(Text = "A1b",
li_attr = list(id = "1,1,2"))
)
),
list(Text = "A2",
li_attr = list(id = "1,2"),
children = list(
list(Text = "A2a",
li_attr = list(id = "1,2,1")),
list(Text = "A2b",
li_attr = list(id = "1,2,2")),
list(Text = "A2c",
li_attr = list(id = "1,2,3"))
)
)
)
)
)