以树为单位显示递归列的列名

时间:2013-08-08 09:33:00

标签: r

是否有(built'in / easy)方式递归显示链接列表的names作为树?(可能输出类似于{{1} shell命令。)

例如,对于列表X,有两列A和B,A在两个子列中包含a1和a2

tree

nametree(x) X ├── A │   ├── a1 │   └── a2 └── B 只会显示names(X)

4 个答案:

答案 0 :(得分:8)

这是一个递归解决方案:

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

使用分支而不是空格显示树结构稍微复杂一些:

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

答案 1 :(得分:4)

一个简单的例子:

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

$B
NULL

这假设您只有一个低于列表一级的数据帧...所以它本身不是递归的,但听起来这与您的数据结构类似。

DrMike和Henrik关于使用str(mylist)的建议将是递归的,并且实际上能够控制结构的深度和输出的显示。

SimonO101的递归示例:

> 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

输出的一些例子:

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

答案 2 :(得分:3)

您可以使用data.tree包。例如:

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

打印出来:

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

或者您可以将数据转换为可打印格式:

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

显示:

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

最后,要显示节点的名称:

names(xtree$children)

打印:

[1] "A" "B"

答案 3 :(得分:1)

这是我想出的,请参阅底部的函数定义。

样本数据:

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

打印短列表的默认方式:

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

命名时限制为前3个项目:

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

将参数传递到print()

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

在非列表项上使用str()而不是print()

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

使用不可见而不是打印来仅显示名称:

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

打印带有限制的长列表:

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

功能代码

#' 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)
}