Display column names of recursive list as tree

Is there a (built-in / easy) way to display the names linked list recursively as a tree? (possibly with an output similar to the tree shell command.)

For example, with a list X with two columns A and B, A in two subcolumns a1 and a2

 nametree(x) X ├── A │  ├── a1 │  └── a2 └── B 

names(X) simply display [1] "A" "B"

+8
source share
4 answers

Here is a recursive solution:

 nametree <- function(X, prefix = "") if( is.list(X) ) for( i in seq_along(X) ) { cat( prefix, names(X)[i], "\n", sep="" ) nametree(X[[i]], paste0(prefix, " ")) } X <- list(X = list( A = list( a1=1:10, a2=1:10 ), B = 1:10 )) nametree(X) # X # A # a1 # a2 # B 

Mapping a tree structure with branches rather than spaces is a bit more complicated:

 nametree <- function(X, prefix1 = "", prefix2 = "", prefix3 = "", prefix4 = "") if( is.list(X) ) for( i in seq_along(X) ) { cat( if(i<length(X)) prefix1 else prefix3, names(X)[i], "\n", sep="" ) prefix <- if( i<length(X) ) prefix2 else prefix4 nametree( X[[i]], paste0(prefix, "├──"), paste0(prefix, "│ "), paste0(prefix, "└──"), paste0(prefix, " ") ) } nametree(X) # X # +--A # ¦ +--a1 # ¦ +--a2 # +--B # +--C # +--a # +--b 
+8
source

A simple example:

 > mylist <- list(A=data.frame(A1=1:3,A2=4:6),B=7:9) > out <- lapply(mylist,names) $A [1] "A1" "A2" $B NULL 

This assumes that you only have data one level below the list ... so it is not recursive in itself, but it looks like it is similar to your data structure.

DrMike and Henrik's suggestion for using str(mylist) will be recursive and, in fact, able to control both the depth of the structure and the display of the output.

SimonO101 recursion example:

 > df <- data.frame( A = runif(3) , B = runif(3) ) > ll <- list( A = df , B = list( C = df , D = df ) , E = 1 ) > str(ll) List of 3 $ A:'data.frame': 3 obs. of 2 variables: ..$ A: num [1:3] 0.948 0.356 0.467 ..$ B: num [1:3] 0.2319 0.7574 0.0312 $ B:List of 2 ..$ C:'data.frame': 3 obs. of 2 variables: .. ..$ A: num [1:3] 0.948 0.356 0.467 .. ..$ B: num [1:3] 0.2319 0.7574 0.0312 ..$ D:'data.frame': 3 obs. of 2 variables: .. ..$ A: num [1:3] 0.948 0.356 0.467 .. ..$ B: num [1:3] 0.2319 0.7574 0.0312 $ E: num 1 

Some examples of output:

 > str(mylist) List of 2 $ A:'data.frame': 3 obs. of 2 variables: ..$ A1: int [1:3] 1 2 3 ..$ A2: int [1:3] 4 5 6 $ B: int [1:3] 7 8 9 > str(mylist, give.attr=FALSE, give.length=FALSE, give.head=FALSE, vec.len=0, indent.str="|", comp.str="----") List of 2 |----A:'data.frame': 3 obs. of 2 variables: | ..$ A1:NULL ... | ..$ A2:NULL ... |----B:NULL ... 
+4
source

You can use the data.tree package. For instance:

 x <- list( A = list( a1 = list(data = 1:10), b1 = list(data = 1:100 )), B = list(data = c(1, 3, 5) )) library(data.tree) xtree <- FromListSimple(x, nodeName = "X") xtree 

This produces:

  levelName 1 X 2 ¦--A 3 ¦ ¦--a1 4 ¦ °--b1 5 °--B 

Or you can convert the data to a print format:

 print(xtree, maxData = function(node) if (is.null(node$data)) 0 else max(node$data)) 

Which shows:

  levelName maxData 1 X 0 2 ¦--A 0 3 ¦ ¦--a1 10 4 ¦ °--b1 100 5 °--B 5 

Finally, to show the names of the node:

 names(xtree$children) 

Fingerprints:

 [1] "A" "B" 
+3
source

Here is what I came up with, see function definition below.

sample data:

 # a short list l1 <- list(a = factor("1"), b = c(u = 3, v = 4), d= list(x=5, y =6), e= 8, f = 9) # a longer list l2 <- replicate(100, l1, simplify = F) 

default short list printing method:

 print_list(l1) #> $a #> [1] 1 #> Levels: 1 #> $b #> uv #> 3 4 #> $d #> $x #> [1] 5 #> $y #> [1] 6 #> $e #> [1] 8 #> $f #> [1] 9 

restrict the first 3 elements in the name:

 print_list(l1,n_named = 3) #> $a #> [1] 1 #> Levels: 1 #> $b #> uv #> 3 4 #> $d #> $x #> [1] 5 #> $y #> [1] 6 #> # + 2 named items 

pass parameters to print()

 print_list(l1, quote = TRUE) #> $a #> [1] "1" #> Levels: "1" #> $b #> uv #> 3 4 #> $d #> $x #> [1] 5 #> $y #> [1] 6 #> $e #> [1] 8 #> $f #> [1] 9 

use str() instead of print() on elements not on the list:

 print_list(l1, fun = str) #> $a #> Factor w/ 1 level "1": 1 #> $b #> Named num [1:2] 3 4 #> - attr(*, "names")= chr [1:2] "u" "v" #> $d #> $x #> num 5 #> $y #> num 6 #> $e #> num 8 #> $f #> num 9 

use an invisible rather than a printed form to display only names:

 print_list(l1, fun = invisible) #> $a #> #> $b #> #> $d #> $x #> #> $y #> #> $e #> #> $f #> 

print a long list with restrictions:

 print_list(l2,n_named = 3, n_unnamed = 2) #> [[1]] #> $a #> [1] 1 #> Levels: 1 #> $b #> uv #> 3 4 #> $d #> $x #> [1] 5 #> $y #> [1] 6 #> # + 2 named items #> [[2]] #> $a #> [1] 1 #> Levels: 1 #> $b #> uv #> 3 4 #> $d #> $x #> [1] 5 #> $y #> [1] 6 #> # + 2 named items #> # + 98 items 

function code

 #' print list nicely #' #' @param l list to print #' @param n_named max number of named items to display if list/sublist contains only named items #' @param n_unnamed max number of items to display if list/sublist contains unnamed items #' @param fun function to use to print non list items #' @param ... additional arguments passed to fun #' #' @return unchanged input #' @export print_list <- function(l, n_named = 20, n_unnamed = 6, fun = print, ...){ dots <- list(...) fun0 <- function(l) do.call(fun, c(list(l),dots)) print_list0(l, nm = NULL, i = NULL, indent = -2, n_named = n_named, n_unnamed = n_unnamed , fun = fun0) } print_list0 <- function(l, nm = NULL, i = NULL, indent=-2, n_named = 20, n_unnamed = 6, fun){ if(!is.null(nm)){ if(nm!=""){ cat(strrep(" ", indent), "$", nm,"\n",sep="") } else { cat(strrep(" ", indent), "[[", i,"]]\n",sep="") } } if(is.data.frame(l) || !is.list(l)){ output <- capture.output(fun(l)) output <- paste(strrep(" ", indent), output, collapse="\n") cat(output,"\n") } else { nm = allNames(l) named <- all(nm != "") if(named && length(l) > n_named){ n_unshowed <- length(l) - n_named l <- l[seq_len(n_named)] nm <- nm[seq_len(n_named)] Map(print_list0, l, nm, i = seq_along(l), indent=indent+2, n_named = n_named, n_unnamed = n_unnamed, fun = replicate(length(l), fun)) cat(strrep(" ", indent+2), "# + ", n_unshowed, " named items\n",sep="") } else if(length(l) > n_unnamed){ n_unshowed <- length(l) - n_unnamed l <- l[seq_len(n_unnamed)] nm <- nm[seq_len(n_unnamed)] Map(print_list0, l, nm, i = seq_along(l), indent=indent+2, n_named = n_named, n_unnamed = n_unnamed, fun = replicate(length(l), fun)) cat(strrep(" ", indent+2), "# + ", n_unshowed, " items\n",sep="") } else { Map(print_list0, l, nm, i = seq_along(l), indent=indent+2, n_named = n_named, n_unnamed = n_unnamed, fun = replicate(length(l), fun)) } } invisible(l) } 
+1
source

Source: https://habr.com/ru/post/951292/


All Articles