Convert the R dataframe to the nested list as required

66 views Asked by At

I have a dataframe as follows:

df <- data.frame(
      all = c("All product","All product","All product","All product","All product","All product","All product","All product",
              "All product","All product","All product","All product","All product","All product","All product","All product"),
      category = c("Agriculture","Agriculture","Agriculture","Agriculture", "Agriculture","Agriculture","Agriculture","Agriculture",
                   "Non Agriculture", "Non Agriculture", "Non Agriculture", "Non Agriculture","Non Agriculture", "Non Agriculture", "Non Agriculture", "Non Agriculture"),
      HS2 = c("01","01","01","01","02","02","02","02","03","03","03","03","04","04","04","04"),
      HS4 = c("0101","0101","0102","0102","0201","0201","0202","0202","0301","0301","0302","0302","0401","0401","0402","0402"),
      HS6 = c("010101","010102", "010201","010202","020101","020102","020201","020202","030101","030102", "030201","030202","040101","040102","040201","040202")
    )

I want to be able to convert this dataframe in a nested list as follows:

 nodes <- list(
      list(
        text = "All product",
        type = "root",
        children = list(
          list(
            text = "Agriculture",
            type = "child",
            children= list( 
              list(
                text = "01",
                type = "child",
                children= list( 
                  list(
                    text = "0101",
                    type = "child",
                    children= list( 
                      list(
                        text = "010101",
                        type = "child"
                        ),
                      list(
                        text = "010102",
                        type = "child"
                      )
                      )
                    ),
                  list(
                    text = "0102",
                    type = "child",
                    children= list( 
                      list(
                        text = "010201",
                        type = "child"
                      ),
                      list(
                        text = "010202",
                        type = "child"
                      )
                    )
                  )
                  )
                
                ),
              list(
                text = "02",
                type = "child",
                children= list( 
                  list(
                    text = "0201",
                    type = "child",
                    children= list( 
                      list(
                        text = "020101",
                        type = "child"
                      ),
                      list(
                        text = "020102",
                        type = "child"
                      )
                    )
                  ),
                  list(
                    text = "0202",
                    type = "child",
                    children= list( 
                      list(
                        text = "020201",
                        type = "child"
                      ),
                      list(
                        text = "020202",
                        type = "child"
                      )
                    )
                  )
                )
                
              )
              )
          ),
          list(
            text = "Non Agriculture",
            type = "child",
            children= list( 
              list(
                text = "03",
                type = "child",
                children= list( 
                  list(
                    text = "0301",
                    type = "child",
                    children= list( 
                      list(
                        text = "030101",
                        type = "child"
                      ),
                      list(
                        text = "030102",
                        type = "child"
                      )
                    )
                  ),
                  list(
                    text = "0302",
                    type = "child",
                    children= list( 
                      list(
                        text = "030201",
                        type = "child"
                      ),
                      list(
                        text = "030202",
                        type = "child"
                      )
                    )
                  )
                )
                
              ),
              list(
                text = "04",
                type = "child",
                children= list( 
                  list(
                    text = "0401",
                    type = "child",
                    children= list( 
                      list(
                        text = "040101",
                        type = "child"
                      ),
                      list(
                        text = "040102",
                        type = "child"
                      )
                    )
                  ),
                  list(
                    text = "0402",
                    type = "child",
                    children= list( 
                      list(
                        text = "040201",
                        type = "child"
                      ),
                      list(
                        text = "040202",
                        type = "child"
                      )
                    )
                  )
                )
                
              )
            )
          )
        )
      )
    )

I have written the list manually. However my scenario is that I will have a dataframe as I stated above and the dataframe data can change anytime but not the structure. How can I convert the dataframe to the nested list I shared.

1

There are 1 answers

6
Stéphane Laurent On

Here is a way. I took the makeNodes function from an example given in the jsTreeR package.

# make the nodes list from a vector of file paths
makeNodes <- function(leaves){
  dfs <- lapply(strsplit(leaves, "/"), function(s){
    item <-
      Reduce(function(a,b) paste0(a,"/",b), s[-1], s[1], accumulate = TRUE)
    data.frame(
      item = item,
      parent = c("root", item[-length(item)]),
      stringsAsFactors = FALSE
    )
  })
  dat <- dfs[[1]]
  for(i in 2:length(dfs)){
    dat <- merge(dat, dfs[[i]], all = TRUE)
  }
  f <- function(parent){
    i <- match(parent, dat$item)
    item <- dat$item[i]
    children <- dat$item[dat$parent==item]
    label <- tail(strsplit(item, "/")[[1]], 1)
    if(length(children)){
      list(
        text = label,
        type = "child",
        children = lapply(children, f)
      )
    }else{
      list(text = label, type = "child")
    }
  }
  lapply(dat$item[dat$parent == "root"], f)
}

# the dataframe
df <- data.frame(
  all = c("All product","All product","All product","All product","All product","All product","All product","All product",
          "All product","All product","All product","All product","All product","All product","All product","All product"),
  category = c("Agriculture","Agriculture","Agriculture","Agriculture", "Agriculture","Agriculture","Agriculture","Agriculture",
               "Non Agriculture", "Non Agriculture", "Non Agriculture", "Non Agriculture","Non Agriculture", "Non Agriculture", "Non Agriculture", "Non Agriculture"),
  HS2 = c("01","01","01","01","02","02","02","02","03","03","03","03","04","04","04","04"),
  HS4 = c("0101","0101","0102","0102","0201","0201","0202","0202","0301","0301","0302","0302","0401","0401","0402","0402"),
  HS6 = c("010101","010102", "010201","010202","020101","020102","020201","020202","030101","030102", "030201","030202","040101","040102","040201","040202")
)

# transform it to a vector of paths
paths <- apply(df, 1, function(x) paste0(x, collapse = "/"))

# make the nodes list
nodes <- makeNodes(paths)

# we just have to replace 'type="child"' with 'type="root"' at the root
nodes[[1]]$type <- "root"

# let's visualize the result as JSON
jsonlite::toJSON(nodes, auto_unbox = TRUE, pretty = TRUE)
# [
#   {
#     "text": "All product",
#     "type": "root",
#     "children": [
#       {
#         "text": "Agriculture",
#         "type": "child",
#         "children": [
#           {
#             "text": "01",
#             "type": "child",
#             "children": [
#               {
#                 "text": "0101",
#                 "type": "child",
#                 "children": [
#                   {
#                     "text": "010101",
#                     "type": "child"
#                   },
#                   {
#                     "text": "010102",
#                     "type": "child"
#                   }
#                 ]
#               },
#               {
#                 "text": "0102",
#                 "type": "child",
#                 "children": [
#                   {
#                     "text": "010201",
#                     "type": "child"
#                   },
#                   {
#                     "text": "010202",
#                     "type": "child"
#                   }
#                 ]
#               }
#             ]
#           },
#           {
#             "text": "02",
#             "type": "child",
#             "children": [
#               {
#                 "text": "0201",
#                 "type": "child",
#                 "children": [
#                   {
#                     "text": "020101",
#                     "type": "child"
#                   },
#                   {
#                     "text": "020102",
#                     "type": "child"
#                   }
#                 ]
#               },
#               {
#                 "text": "0202",
#                 "type": "child",
#                 "children": [
#                   {
#                     "text": "020201",
#                     "type": "child"
#                   },
#                   {
#                     "text": "020202",
#                     "type": "child"
#                   }
#                 ]
#               }
#             ]
#           }
#         ]
#       },
#       {
#         "text": "Non Agriculture",
#         "type": "child",
#         "children": [
#           {
#             "text": "03",
#             "type": "child",
#             "children": [
#               {
#                 "text": "0301",
#                 "type": "child",
#                 "children": [
#                   {
#                     "text": "030101",
#                     "type": "child"
#                   },
#                   {
#                     "text": "030102",
#                     "type": "child"
#                   }
#                 ]
#               },
#               {
#                 "text": "0302",
#                 "type": "child",
#                 "children": [
#                   {
#                     "text": "030201",
#                     "type": "child"
#                   },
#                   {
#                     "text": "030202",
#                     "type": "child"
#                   }
#                 ]
#               }
#             ]
#           },
#           {
#             "text": "04",
#             "type": "child",
#             "children": [
#               {
#                 "text": "0401",
#                 "type": "child",
#                 "children": [
#                   {
#                     "text": "040101",
#                     "type": "child"
#                   },
#                   {
#                     "text": "040102",
#                     "type": "child"
#                   }
#                 ]
#               },
#               {
#                 "text": "0402",
#                 "type": "child",
#                 "children": [
#                   {
#                     "text": "040201",
#                     "type": "child"
#                   },
#                   {
#                     "text": "040202",
#                     "type": "child"
#                   }
#                 ]
#               }
#             ]
#           }
#         ]
#       }
#     ]
#   }
# ]