Get names at deepest level of a nested list in R

Viewed 213

I'm been working with nested lists and recursive functions in R following this instructions. Now there is just one piece I miss to design an own function, which is getting a vector with the respective names sorted from the highest to the deepest level.

The input list is:

lst <- list(
    title = "References and Plant Communities in 'SWEA-Dataveg'",
    author = "Miguel Alvarez",
    date = "Dezember 28, 2019",
    "header-includes" = c(
        "- \\usepackage[utf8]{inputenc}",
        "- \\usepackage[T1]{fontenc}", "- \\usepackage{bibentry}",
        "- \\nobibliography{sweareferences.bib}"),
    output = list(pdf_document=list(citation_package="natbib")),
    "biblio-style" = "unsrtnat",
    bibliography = "sweareferences.bib",
    papersize = "a4")

The structure of the output list will then looks like this (printed in the console). Herewith note the vector at lst$output$pdf_document$citation_package:

$title
[1] "title"

$author
[1] "author"

$date
[1] "date"

$`header-includes`
[1] "header-includes"

$output
$output$pdf_document
$output$pdf_document$citation_package
[1] "output"
[2] "pdf_document"
[3] "citation_package"

$`biblio-style`
[1] "biblio-style"

$bibliography
[1] "bibliography"

$papersize
[1] "papersize"

Of course, the function has to be recursive to be applied in any different case.

2 Answers

Here is one possible approach, using only base R. The following function f replaces each terminal node (or "leaf") of a recursive list x with the sequence of names leading up to it. It treats unnamed lists like named lists with all names equal to "", which is a useful generalization.

f <- function(x, s = NULL) {
  if (!is.list(x)) {
    return(s)
  }
  nms <- names(x)
  if (is.null(nms)) {
    nms <- character(length(x))
  }
  Map(f, x = x, s = Map(c, list(s), nms))
}

f(lst)
$title
[1] "title"

$author
[1] "author"

$date
[1] "date"

$`header-includes`
[1] "header-includes"

$output
$output$pdf_document
$output$pdf_document$citation_package
[1] "output"           "pdf_document"     "citation_package"



$`biblio-style`
[1] "biblio-style"

$bibliography
[1] "bibliography"

$papersize
[1] "papersize"

Using an external package, this can be done quite efficiently with rrapply() in the rrapply-package:

rrapply::rrapply(lst, f = function(x, .xparents) .xparents)

#> $title
#> [1] "title"
#> 
#> $author
#> [1] "author"
#> 
#> $date
#> [1] "date"
#> 
#> $`header-includes`
#> [1] "header-includes"
#> 
#> $output
#> $output$pdf_document
#> $output$pdf_document$citation_package
#> [1] "output"           "pdf_document"     "citation_package"
#> 
#> 
#> 
#> $`biblio-style`
#> [1] "biblio-style"
#> 
#> $bibliography
#> [1] "bibliography"
#> 
#> $papersize
#> [1] "papersize"
Related