Home > Back-end >  How can I flatten a multilevel nested list to a specified depth?
How can I flatten a multilevel nested list to a specified depth?

Time:02-12

I am trying to flatten a list that has 3 levels into a list that has 2 levels.... In other words, I have a nested list as such :

ls <- list(
  a = list(
    a1 = list(
       a11 = list(data),
    a2 = list(
       a21 = list(data2)),
  b = list(
    b1 = list(
       b11 = list(data3),
    b2 = list(
       b21 = list(data4)))
  

I would like to flatten this so that it looks like this:

flat_ls <- list(
  a_a1 = list(
     a11 = list(data),
  a_a2 = list(
     a21 = list(data2)),
  b_b1 = list(
     b11 = list(data3),
  b_b2 = list(
     b21 = list(data4)))
  

I know there function flatten() or lapply(rapply(y, enquote, how="unlist"), eval) can make a multilevel list into a flat list. However, I want to keep the last layer of the list, without flattening that. How can I accomplish this?

CodePudding user response:

purrr::flatten() actually does exactly what you're looking for. per (purrr) the documentation, flatten() and friends "only ever remove a single layer of hierarchy."

library(purrr)

# placeholder values for `data` etc
data <- as.symbol("data")
data2 <- as.symbol("data2")
data3 <- as.symbol("data3")
data4 <- as.symbol("data4")

# added a few missing parens; raised error in original
ls <- list(
  a = list(
    a1 = list(
      a11 = list(data)
    ),
    a2 = list(
      a21 = list(data2)
    )
  ),
  b = list(
    b1 = list(
      b11 = list(data3)
    ),
    b2 = list(
      b21 = list(data4)
    )
  )
)

# (added step in response to comment): 
# combine top two levels of names
ls_renamed <- imap(ls, ~ set_names(.x, paste(.y, names(.x), sep = "_")))

# flatten top level
flat_ls <- flatten(ls_renamed)

dput(flat_ls)
# list(
#   a_a1 = list(
#     a11 = list(data)
#   ), 
#   a_a2 = list(
#     a21 = list(data2)
#   ), 
#   b_b1 = list(
#     b11 = list(data3)
#   ), 
#   b_b2 = list(
#     b21 = list(data4)
#   )
# )
  • Related