I have an arbitrarily deep list that contains an arbitrary number of named character vectors. A simple example might be:
d <- c("foo", "bar")
names(d) <- c("d1", "d2")
e <- c("bar","foo")
names(e) <- c("d1", "d3")
l <- list(a1 = list(b1 = list(c1 = d, c2 = e), a2 = list(b1 = e)))
l
$a1
$a1$b1
$a1$b1$c1
d1 d2
"foo" "bar"
$a1$b1$c2
d1 d3
"bar" "foo"
$a1$a2
$a1$a2$b1
d1 d3
"bar" "foo"
Id like to collect the (full) name at each leaf; for example,
collect_names(l)
"$a1$b1$c1" "$a1$b1$c2" "$a1$a2$b1"
A general solution that compares efficiency at the different "levels of arbitrary" gets extra credit ;)
wdots <- names(rapply(l,length))
This works for the example given, but I only found it thanks to @flodel's comment. If you want the dollar symbols, there's
wdols <- gsub('\\.','\\$',wdots)
though, as @thelatemail pointed out, this will not give you what you want if any of the names in your hierarchy contain "."
This recursive function seems to work:
collect_names <- function(l) {
if (!is.list(l)) return(NULL)
names <- Map(paste, names(l), lapply(l, collect_names), sep = "$")
gsub("\\$$", "", unlist(names, use.names = FALSE))
}
collect_names(l)
# [1] "a1$b1$c1" "a1$b1$c2" "a1$a2$b1"
Other options:
Hierarchical view:
f <- function(x, parent=""){
if(!is.list(x)) return(parent)
mapply(f, x, paste(parent,names(x),sep="$"), SIMPLIFY=FALSE)
}
f(l)
$a1
$a1$b1
$a1$b1$c1
[1] "$a1$b1$c1"
$a1$b1$c2
[1] "$a1$b1$c2"
$a1$a2
$a1$a2$b1
[1] "$a1$a2$b1"
Just the names:
f <- function(x, parent=""){
if(!is.list(x)) return(parent)
unlist(mapply(f, x, paste(parent,names(x),sep="$"), SIMPLIFY=FALSE))
}
f(l)
a1.b1.c1 a1.b1.c2 a1.a2.b1
"$a1$b1$c1" "$a1$b1$c2" "$a1$a2$b1"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With