从列表列表中删除 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 将捕获然后展开它们。我认为只需添加一个额外的&amp;&amp; is.data.frame(x) 就足够了。 @joran -- 谢谢。猜你的意思是&amp;&amp; !is.data.frame(x),对吧?【参考方案2】:

这是一个使用FilterNegate 组合的选项

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 元素的主要内容,如果未能解决你的问题,请参考以下文章

python从列表中删除元素

删除 k 个最后出现的列表元素

从列表的副本中删除时删除的列表元素[重复]

我可以从二维列表中删除列表元素吗? [复制]

如何从列表中删除元素列表?

从包含特定字符的列表中删除元素[重复]