8

是否有(内置/简单)方法可以将互连列表的递归显示为树?names(可能有类似于treeshell 命令的输出。)

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

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

names(X)只会显示[1] "A" "B"

4

4 回答 4

9

这是一个递归解决方案:

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
于 2013-08-08T10:22:22.683 回答
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 ...
于 2013-08-08T09:55:11.040 回答
4

您可以使用 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"
于 2016-05-14T13:00:45.590 回答
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

使用 invisible 而不是 print 仅显示名称:

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

于 2019-09-23T12:37:44.170 回答