Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Extract name hierarchy for each leaf of a nested list

Tags:

r

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 ;)

like image 584
Carson Avatar asked Sep 18 '13 01:09

Carson


3 Answers

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 "."

like image 89
Frank Avatar answered Oct 19 '22 08:10

Frank


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"
like image 22
flodel Avatar answered Oct 19 '22 09:10

flodel


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"
like image 3
Ferdinand.kraft Avatar answered Oct 19 '22 08:10

Ferdinand.kraft