WinterMensch
WinterMensch

Reputation: 653

Get elements from arbitrary nested list

I have a nested list like this one:

nested_list = list(children = list(CV = "hello", 
                                   children = list(CV = "out", 
                                                   children = list(CV = "there", 
                                                                   TE = "blaa")), 
                                   TE = "hello",
                                   children = list(CV = "tom", 
                                                   TE = "lisa", 
                                                   children = list(TE = "bob"))), 
                   children = list(CV = "sam", 
                                   children = list(CV = "out", 
                                                   children = list(CV = "there", 
                                                                   TE = "blaa", 
                                                                   other = "other element"))))

and I need to extract all elements that are named with "CV" or "TE". There might also be elements with other names as CV or TE.

The elements with names "TE" or "CV" can be lists themselves, so I need to extract the lists. Here´s some input with lists as elements that need to be extracted.

nested_list2 = list(children = list(CV = "hello", 
                                   children = list(CV = list(subject = "sub", value = list(key = "1", var = "45")), 
                                                   children = list(CV = "there", 
                                                                   TE = list(subject = "sub2")))))

The problem is the unknown depth level of nested lists. so I need a function that I can use on any nested list.

This is the expected output for nested_list:

exp_output = list(CV = "hello", 
                  CV = "out", 
                  CV = "there", 
                  TE = "blaa", 
                  TE = "hello", 
                  CV = "tom", 
                  TE = "lisa", 
                  TE = "bob", 
                  CV = "sam",
                  CV = "out", 
                  CV = "there", 
                  TE = "blaa")

and this would be the expected output of nested_list2:

exp_output2 = list(CV = list("hello"),
                   CV = list(subject = "sub", value = list(key = "1", var = "45")),
                   CV = list("there"),
                   TE = list(subject = "sub2"))

I know that the list elements will not have unique names, but I need this structure. Is there such a function? I haven´t found anything.

Any help appreciated.

Upvotes: 1

Views: 126

Answers (1)

moodymudskipper
moodymudskipper

Reputation: 47300

You can use a recursive function that appends a list :

res <- list()
fun <- function(x, nms){
  if(any(names(x) %in% nms)){
    res <<- c(res,x[names(x) %in% nms])
    x <- x[!names(x) %in% nms]
  }
  if (is.list(x)) lapply(x,fun,nms)
}
fun(nested_list2, c("CV","TE"))

res <- list()
fun(nested_list, c("CV","TE"))
str(res)
# List of 12
# $ CV: chr "hello"
# $ TE: chr "hello"
# $ CV: chr "out"
# $ CV: chr "there"
# $ TE: chr "blaa"
# $ CV: chr "tom"
# $ TE: chr "lisa"
# $ TE: chr "bob"
# $ CV: chr "sam"
# $ CV: chr "out"
# $ CV: chr "there"
# $ TE: chr "blaa"

res <- list()
fun(nested_list2, c("CV","TE"))
str(res)
# List of 4
# $ CV: chr "hello"
# $ CV:List of 2
# ..$ subject: chr "sub"
# ..$ value  :List of 2
# .. ..$ key: chr "1"
# .. ..$ var: chr "45"
# $ CV: chr "there"
# $ TE:List of 1
# ..$ subject: chr "sub2"

Upvotes: 2

Related Questions