Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get element names in rapply

Tags:

r

The little-used rapply function should be a perfect solution to many problems (such as this one ). However, it leaves the user-written function f with no ability to know where it is in the tree.

Is there any way to pass the name of the element in the nested list to f in an rapply call? Unfortunately, rapply calls .Internal pretty quickly.

like image 283
Ari B. Friedman Avatar asked Feb 01 '13 22:02

Ari B. Friedman


2 Answers

I struggled with nested lists with arbitrary depth recently. Eventually, I came up to more or less acceptable decision in my case. It is not the direct answer to your question (no rapply usage), but it seems to be solving the same kind of problems. I hope it can be of some help.

Instead of trying to access names of list elements inside rapply I generated vector of names and queried it for elements.

# Sample list with depth of 3
mylist <- list(a=-1, b=list(A=1,B=2), c=list(C=3,D=4, E=list(F=5,G=6)))

Generating of names vector is a tricky in my case. Specifically, names of list elements should be safe, i.e. without . symbol.

list.names <- strsplit(names(unlist(mylist)), split=".", fixed=TRUE)
node.names <- sapply(list.names, function(x) paste(x, collapse="$"))
node.names <- paste("mylist", node.names, sep="$")
node.names

[1] "mylist$a"     "mylist$b$A"   "mylist$b$B"   "mylist$c$C"   "mylist$c$D"   "mylist$c$E$F"
[7] "mylist$c$E$G"

Next step is accessing list element by string name. I found nothing better than using temporary file.

f <- function(x){
  fname <- tempfile()
  cat(x, file=fname)
  source(fname)$value
}

Here f just returns value of x, where x is a string with full name of list element.

Finally, we can query list in pseudo-recursive way.

sapply(node.names, f)
like image 60
redmode Avatar answered Oct 21 '22 19:10

redmode


Referring to the question Find the indices of an element in a nested list?, you can write:

rappply <- function(x, f) {
  setNames(lapply(seq_along(x), function(i) {
    if (!is.list(x[[i]])) f(x[[i]], .name = names(x)[i])
    else rappply(x[[i]], f)
  }), names(x)) 
}

then,

> mylist <- list(a = 1, b = list(A = 1, B = 2), c = list(C = 1, D = 3))
> 
> rappply(mylist, function(x, ..., .name) {
+   switch(.name, "a" = 1, "C" = 5, x)
+ })
$a
[1] 1

$b
$b$A
[1] 1

$b$B
[1] 2


$c
$c$C
[1] 5

$c$D
[1] 3
like image 45
kohske Avatar answered Oct 21 '22 18:10

kohske