2

How to turn a data frame into a recursive list of lists (tree)?

Input

roles_data <- data.frame(
  Child = c("A", "B", "C", "D", "E", "F"),
  ParentID = c(NA, "A", "B", "B", "D", "D")  # The top-level role has no parent (NA)
)

Desired Output

desired_output <- list(
 list(
 text = "A",
 children = list(
 list(
 text = "B",
 children = list(
 list(
 text = "C"),
 list(
 text = "D"
 ,
 children = list(
 list(
  text = "E"
 ), 
  list(
  text = "F"
 )  ) ) ) ) ) )

(Hopefully, I did not mess with the output table at the bottom, just need to have more than one level of depth.)

1
  • Can anyone explain the close votes saying this needs details or clarity? It has expected input and output. I thought there was enough here to answer it. Any suggestions to improve the question? Commented Apr 11 at 8:23

1 Answer 1

4

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"
            }
          ]
        }
      ]
    }
  ]
} 
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.