Search code examples
rlistrecursionnested-lists

Is there an R function for unlisting in which one can control the levels of recursion?


I often have nested lists of objects which come from nested lapply statements, so that the objects are in the last level. When I want to "flatten" these lists, I use unlist; however, sometimes I cannot use unlist(recursive = T) because it will also flatten the last object's structure.

Is there any way to control the levels in the list up to which I can apply the unlist recursion? Or is there any other R function that does this?

For example, say I have a list of plots and I want to have them in the same list level to then align all the plots together in a panel.

# Example list
library(ggplot2)

l0 <- list(
  l1 = list(
    l2 = list(
      l3.1 = ggplot(data = data.frame()) + ggtitle("p1"),
      l3.2 = ggplot(data = data.frame()) + ggtitle("p2")
    )
  )
)

# What I can do with unlist()
l0.u <- unlist(l0, recursive = F)
l0.u.r <- unlist(l0, recursive = T)

# The desired output
l0.desired <- unlist(unlist(l0, recursive = F),recursive = F)

Solution

  • Here are several other solutions using rrapply() (in package rrapply), which has a dedicated option how = "flatten" to flatten a nested list based on some condition function:

    ## by class (not a pure list)
    rrapply::rrapply(
      l0,
      condition = \(x) !inherits(x, "list"),
      classes = c("list", "ANY"),
      how = "flatten"
    )
    
    ## by class (ggplot object)
    rrapply::rrapply(
      l0,
      condition = ggplot2::is.ggplot,
      classes = c("list", "ANY"),
      how = "flatten"
    )
    
    ## by name
    rrapply::rrapply(
      l0,
      condition = \(x, .xname) grepl("l3", .xname),
      classes = c("list", "ANY"),
      how = "flatten"
    )
    
    ## by level of nesting
    rrapply::rrapply(
      l0,
      condition = \(x, .xpos) length(.xpos) == 3,
      classes = c("list", "ANY"),
      how = "flatten"
    )