You're describing a tree structure: each parent can have multiple children, but each child has exactly one parent. Searching for tree questions, this is similar in principle to Transform a dataframe into a tree structure list of lists, in the sense that we can start from the root and recurse over children. However, as your input and output data are in a different format, we can do something a little more ergonomic. Basically, for each node, create a list with text = node_name, and if there are children, recursively build a subtree for them.
generate_tree <- function(dat, root = dat$Child[is.na(dat$ParentID)]) {
node <- list(text = root)
children <- na.omit(dat$Child[dat$ParentID == root])
if (length(children) > 0) {
node$children <- lapply(children, \(child) generate_tree(dat, child))
}
node
}
If you really want the outer list() you can wrap it in one:
identical(list(generate_tree(roles_data)), desired_output)
# [1] TRUE
And here is the output as json for printing purposes:
generate_tree(roles_data) |> jsonlite::toJSON(pretty = TRUE, auto_unbox = TRUE)
{
"text": "A",
"children": [
{
"text": "B",
"children": [
{
"text": "C"
},
{
"text": "D",
"children": [
{
"text": "E"
},
{
"text": "F"
}
]
}
]
}
]
}