简体   繁体   English

从列表列表中删除 NULL 元素

[英]Remove NULL elements from list of lists

How do I remove the null elements from a list of lists, like below, in R:如何从列表列表中删除空元素,如下所示,在 R 中:

lll <- list(list(NULL),list(1),list("a"))

The object I want would look like:我想要的对象看起来像:

lll <- list(list(1),list("a"))

I saw a similar answer here: How can I remove an element from a list?我在这里看到了类似的答案: How can I remove an element from a list? but was not able to extend it from simple lists to a list of lists.但无法将其从简单列表扩展到列表列表。

EDIT编辑

Bad example above on my part.我上面的坏例子。 Both answers work on simpler case (above).两个答案都适用于更简单的情况(上图)。 What if list is like:如果列表是这样的怎么办:

lll <- list(list(NULL),list(1,2,3),list("a","b","c"))

How to get:怎么获得:

lll <- list(list(1,2,3),list("a","b","c"))

This recursive solution has the virtue of working on even more deeply nested lists.这种递归解决方案的优点是可以处理更深的嵌套列表。

It's closely modeled on Gabor Grothendieck's answer to this quite similar question .它与 Gabor Grothendieck 对这个非常相似的问题的回答密切相关。 My modification of that code is needed if the function is to also remove objects like list(NULL) (not the same as NULL ), as you are wanting.如果该函数还根据需要删除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"

Here is an example of its application to a more deeply nested list, on which the other currently proposed solutions variously fail.这是将其应用于更深层嵌套列表的示例,在该列表上其他当前提出的解决方案各不相同。

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"

Here's an option using Filter and Negate combination这是一个使用FilterNegate组合的选项

Filter(Negate(function(x) is.null(unlist(x))), lll)
# [[1]]
# [[1]][[1]]
# [1] 1
#
#
# [[2]]
# [[2]][[1]]
# [1] "a"

Using purrr使用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"

For this particular example you can also use unlist with its recursive argument.对于此特定示例,您还可以将unlist与其recursive参数一起使用。

lll[!sapply(unlist(lll, recursive=FALSE), is.null)]
# [[1]]
# [[1]][[1]]
# [1] 1
#
#
# [[2]]
# [[2]][[1]]
# [1] "a"

Since you have lists in lists, you probably need to run l/sapply twice, like:由于列表中有列表,您可能需要运行l/sapply两次,例如:

lll[!sapply(lll,sapply,is.null)]

#[[1]]
#[[1]][[1]]
#[1] 1
#
#
#[[2]]
#[[2]][[1]]
#[1] "a"

There is a new package rlist on CRAN, thanks to Kun Ren for making our life easier. CRAN 上有一个新的包rlist ,感谢 Kun Ren 让我们的生活更轻松。

    list.clean(.data, fun = is.null, recursive = FALSE)

or for recursive removal of NULL:或递归删除NULL:

    list.clean(.data, fun = is.null, recursive = TRUE)

Quick fix on Josh O'Brien's solution.快速修复 Josh O'Brien 的解决方案。 There's a bit of an issue with lists of functions函数列表有点问题

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)
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM