是否有(内置/简单)方法可以将互连列表的递归显示为树?names
(可能有类似于tree
shell 命令的输出。)
例如列表 X,有两列 A 和 B,A 包含在两个子列 a1 和 a2 中
nametree(x)
X
├── A
│ ├── a1
│ └── a2
└── B
names(X)
只会显示[1] "A" "B"
是否有(内置/简单)方法可以将互连列表的递归显示为树?names
(可能有类似于tree
shell 命令的输出。)
例如列表 X,有两列 A 和 B,A 包含在两个子列 a1 和 a2 中
nametree(x)
X
├── A
│ ├── a1
│ └── a2
└── B
names(X)
只会显示[1] "A" "B"
这是一个递归解决方案:
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
一个简单的例子:
> 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 ...
您可以使用 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"
这是我想出的,请参阅底部的函数定义。
样本数据:
# 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)
}