在嵌套的列表列表

时间:2016-07-07 14:22:38

标签: r nested-lists

给定一个任意嵌套的列表,如何查找列表是否包含空列表?请考虑以下示例:

mylist <- list(list("foo", "bar", "baz", list(list())))

我尝试rapply,但跳过了列表。虽然我可以使用lapply,但我需要事先知道嵌套的级别。对于本练习,我不需要知道列表的位置(虽然这将是一个奖励),我只需要一种方法来检测是否有一个。

3 个答案:

答案 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