How to flatten nested list keeping inner structure

Let's say I have the following list (result), which is a nested list that captures information from a model: parameters (betas) and their standard errors (sd), additionally with some information regarding the global model (method) and the number of observations (n).

I want to flatten the lists betas and sd while distinguishing where each value of x1 and x2 comes from (i.e. if they are from betas or sd).

Please gently consider the following example:

result<- list(n       = 100,
              method  = "tree", 
              betas   = list(x1 = 1.47,
                             x2 = -2.85),
              sd      = list(x1 = 0.55,
                             x2 = 0.25))

str(result)
# List of 4
# $ n         : num 100
# $ iterations: num 50
# $ betas     :List of 2
# ..$ x1: num 1.47
# ..$ x2: num -2.85
# $ sd        :List of 2
# ..$ x1: num 0.55
# ..$ x2: num 0.25

First attempt: flatten(). [Spoiler(!): I lose the precedence of each value]

## I can't distinguish between betas and sd.
flatten(result)

# $n
# [1] 100
# 
# $iterations
# [1] 50
# 
# $x1
# [1] 1.47
# 
# $x2
# [1] -2.85
# 
# $x1
# [1] 0.55
#
# $x2
# [1] 0.25

Second attempt: unlist(). [Spoiler(!), I need a list, not an atomic vector]

#I need a list 
unlist(result)

# n iterations   betas.x1   betas.x2      sd.x1      sd.x2 
# 100.00      50.00       1.47      -2.85       0.55       0.25 

Desired Output.

list(n        = 100,
    method   = "tree", 
    betas.x1 = 1.47,
    betas.x2 = -2.85,
    sd.x1    = 0.55,
    sd.x2    = 0.25)

# List of 6
# $ n       : num 100
# $ method  : chr "tree"
# $ betas.x1: num 1.47
# $ betas.x2: num -2.85
# $ sd.x1   : num 0.55
# $ sd.x2   : num 0.25

Upvotes: 0

Views: 158

Answers (1)

r2evans
r2evans

Reputation: 160407

as.data.frame will flatten for you. From ?as.data.frame:

Arrays with more than two dimensions are converted to matrices by 'flattening' all dimensions after the first and creating suitable column labels.

Which does a poor job of explaining that it operates on nested lists as well, not just arrays. (In other words, I think the docs do not discuss this feature on non-arrays.)

str(as.data.frame(result))
# 'data.frame': 1 obs. of  6 variables:
#  $ n       : num 100
#  $ method  : chr "tree"
#  $ betas.x1: num 1.47
#  $ betas.x2: num -2.85
#  $ sd.x1   : num 0.55
#  $ sd.x2   : num 0.25

If you don't want/need a list, just as.list it next:

str(as.list(as.data.frame(result)))
# List of 6
#  $ n       : num 100
#  $ method  : chr "tree"
#  $ betas.x1: num 1.47
#  $ betas.x2: num -2.85
#  $ sd.x1   : num 0.55
#  $ sd.x2   : num 0.25

Upvotes: 5

Related Questions