给定一个任意嵌套的列表,如何查找列表是否包含空列表?请考虑以下示例:
mylist <- list(list("foo", "bar", "baz", list(list())))
我尝试rapply
,但跳过了列表。虽然我可以使用lapply
,但我需要事先知道嵌套的级别。对于本练习,我不需要知道列表的位置(虽然这将是一个奖励),我只需要一种方法来检测是否有一个。
答案 0 :(得分:8)
这样的功能呢?
has_empty_list <- function(x) {
if(is.list(x)) {
if (length(x)==0) {
return(TRUE)
} else {
return(any(vapply(x, has_empty_list, logical(1))))
}
} else {
return(FALSE)
}
}
基本上我们创建一个递归函数来查找长度为0的列表。
has_empty_list( list(list("foo", "bar", "baz", list(list()))) )
# TRUE
has_empty_list( list(list("foo", "bar", "baz", list(list(4)))) )
# FALSE
这是一个修改,以找到空列表的索引
find_empty_list <- function(x, index=c()) {
if(is.list(x)) {
#list
if (length(x)==0) {
if (length(index)==0) {
return(0)
} else {
return(index)
}
} else {
m <- Map(find_empty_list, x, lapply(seq_along(x), function(i) append(index,i)))
# return the most deeply nested
return( m[[which.max(lengths(m))]] )
}
} else {
return(numeric())
}
}
这应返回索引的向量,您可以使用该向量来查找空列表。例如
( i <- find_empty_list(mylist) )
# [1] 1 4 1
mylist[[i]]
# list()
如果第一个参数本身是一个空列表,它将返回0
find_empty_list(list())
# 0
如果没有空列表,则应返回空向量
find_empty_list(list(1:3, list("c", a~b)))
# numeric()
答案 1 :(得分:5)
使用嵌套列表的另一个方便选项是使用data.tree
包:
library(data.tree)
nodes <- as.Node(mylist)
any(node$Get(function(node) length(as.list(node))) == 0)
# [1] TRUE
答案 2 :(得分:0)
另一种方法是在rrapply
程序包(base-rrapply
的扩展)中使用rrapply
:
library(rrapply)
## check if any empty list exists
any(
rrapply(mylist,
classes = "list",
condition = function(x) length(x) < 1,
f = function(x) TRUE,
deflt = FALSE,
how = "unlist"
)
)
#> [1] TRUE
更新上面的调用以返回任何空列表的索引向量很简单:
## return flat list with position vectors of empty list
rrapply(mylist,
classes = "list",
condition = function(x) length(x) < 1,
f = function(x, .xpos) .xpos,
how = "flatten"
)
#> [[1]]
#> [1] 1 4 1
在这里,我们使用.xpos
参数,该参数的值将计算为当前正在评估的列表元素的位置。
请注意,这会自动返回所有空列表位置,而不是仅返回一个:
mylist2 <- list(list("foo", list(), "baz", list(list())))
rrapply(mylist2,
classes = "list",
condition = function(x) length(x) < 1,
f = function(x, .xpos) .xpos,
how = "flatten"
)
#> [[1]]
#> [1] 1 2
#>
#> [[2]]
#> [1] 1 4 1
## using MrFlick's find_empty_list function
find_empty_list(mylist2)
#> [1] 1 4 1