Derive names of R list elements, but ignore data.frame column names

Viewed 123

Desired

is having a R function

listNames = function(l) {
   # return list element names
}

that returns all list elements, but ignores the column names of data frames on first level

listNames(a)
[1] "b.df1" "b.e" "c" "df2"  

from a nested list:

a = list(b = list(df1 = data.frame(col = c(1,2)), e = NULL), c = NULL, df2 = data.frame(c12 = c(1,2),c34 = c(3,4)))

Tried so far

unlist returns also data.frame columns. I assume because data.frames are also considered lists

names(unlist(a,recursive = FALSE))
[1] "b.df1"   "b.e"     "df2.c12" "df2.c34"

and names(a) skips nested elements

names(a)
[1] "b"   "c"   "df2"
2 Answers

You can write a recursive function stopping when there is no list or a data.frame.

listNames = function(l) {
  if(!is.list(l) | is.data.frame(l)) TRUE
  else (lapply(l, listNames))
}

names(unlist(listNames(a)))
#[1] "b.df1" "b.e"   "c"     "df2"

Using an external package, this can be done with rrapply::rrapply(), which extends base rapply to avoid recursing into individual data.frame columns.

One possible approach is to include "data.frame" in the evaluated classes and return the name of each evaluated element, which works for arbitrary levels of nesting:

library(rrapply)

rrapply(a, classes = c("ANY", "data.frame"), f = function(x, .xname) .xname, how = "unlist")

#> b.df1   b.e     c   df2 
#> "df1"   "e"   "c" "df2"
Related