从列表列表中删除 NULL 元素
Posted
技术标签:
【中文标题】从列表列表中删除 NULL 元素【英文标题】:Remove NULL elements from list of lists 【发布时间】:2014-12-19 18:59:17 【问题描述】:如何从 R 中的列表列表中删除空元素,如下所示:
lll <- list(list(NULL),list(1),list("a"))
我想要的对象看起来像:
lll <- list(list(1),list("a"))
我在这里看到了类似的答案:How can I remove an element from a list?,但无法将其从简单列表扩展到列表列表。
编辑
就我而言,上面的例子很糟糕。两个答案都适用于更简单的情况(上图)。如果列表是这样的:
lll <- list(list(NULL),list(1,2,3),list("a","b","c"))
如何获得:
lll <- list(list(1,2,3),list("a","b","c"))
【问题讨论】:
也许接受以下解决方案之一? 【参考方案1】:这种递归解决方案具有处理更深嵌套列表的优点。
它非常模仿 Gabor Grothendieck 对 this quite similar question 的回答。如果函数还需要删除像list(NULL)
(与NULL
不同)这样的对象,则需要我修改该代码。
## A helper function that tests whether an object is either NULL _or_
## a list of NULLs
is.NullOb <- function(x) is.null(x) | all(sapply(x, is.null))
## Recursively step down into list, removing all such objects
rmNullObs <- function(x)
x <- Filter(Negate(is.NullOb), x)
lapply(x, function(x) if (is.list(x)) rmNullObs(x) else x)
rmNullObs(lll)
# [[1]]
# [[1]][[1]]
# [1] 1
#
#
# [[2]]
# [[2]][[1]]
# [1] "a"
这是一个将其应用于更深层嵌套列表的示例,其他当前提出的解决方案在该列表上都失败了。
LLLL <- list(lll)
rmNullObs(LLLL)
# [[1]]
# [[1]][[1]]
# [[1]][[1]][[1]]
# [[1]][[1]][[1]][[1]]
# [1] 1
#
#
# [[1]][[1]][[2]]
# [[1]][[1]][[2]][[1]]
# [1] "a"
【讨论】:
这个功能很棒! @mrp -- 谢谢!很高兴我能够将这个方便的模板传递给其他人。 fyi,如果您的列表元素主要是数据框,这可能会以一种可能无法预期的方式运行,因为is.list
将捕获然后展开它们。我认为只需添加一个额外的&& is.data.frame(x)
就足够了。
@joran -- 谢谢。猜你的意思是&& !is.data.frame(x)
,对吧?【参考方案2】:
这是一个使用Filter
和Negate
组合的选项
Filter(Negate(function(x) is.null(unlist(x))), lll)
# [[1]]
# [[1]][[1]]
# [1] 1
#
#
# [[2]]
# [[2]][[1]]
# [1] "a"
【讨论】:
我正在处理 S4 对象列表,这个解决方案是唯一有效的解决方案,谢谢!【参考方案3】:使用purrr
purrr::map(lll, ~ purrr::compact(.)) %>% purrr::keep(~length(.) != 0)
[[1]]
[[1]][[1]]
[1] 1
[[1]][[2]]
[1] 2
[[1]][[3]]
[1] 3
[[2]]
[[2]][[1]]
[1] "a"
[[2]][[2]]
[1] "b"
[[2]][[3]]
[1] "c"
【讨论】:
【参考方案4】:对于这个特定示例,您还可以使用 unlist
及其 recursive
参数。
lll[!sapply(unlist(lll, recursive=FALSE), is.null)]
# [[1]]
# [[1]][[1]]
# [1] 1
#
#
# [[2]]
# [[2]][[1]]
# [1] "a"
【讨论】:
【参考方案5】:由于列表中有列表,您可能需要运行两次l/sapply
,例如:
lll[!sapply(lll,sapply,is.null)]
#[[1]]
#[[1]][[1]]
#[1] 1
#
#
#[[2]]
#[[2]][[1]]
#[1] "a"
【讨论】:
【参考方案6】:CRAN 上有一个新包rlist,感谢坤仁让我们的生活更轻松。
list.clean(.data, fun = is.null, recursive = FALSE)
或用于递归删除 NULL:
list.clean(.data, fun = is.null, recursive = TRUE)
【讨论】:
包名是什么?链接? 抱歉耽搁了@not2qubit,包的名字是上面提到的RLIST【参考方案7】:快速修复 Josh O'Brien 的解决方案。函数列表有点问题
is.NullOb <- function(x) if(!(is.function(x))) is.null(x) | all(sapply(x, is.null)) else FALSE
## Recursively step down into list, removing all such objects
rmNullObs <- function(x)
if(!(is.function(x)))
x = x[!(sapply(x, is.NullOb))]
lapply(x, function(x) if (is.list(x)) rmNullObs(x) else x)
【讨论】:
以上是关于从列表列表中删除 NULL 元素的主要内容,如果未能解决你的问题,请参考以下文章