有效地删除列表和所有子列表中的所有NULL值

Kun*_*Ren 16 null r list

请考虑以下列表:

> l1 <- list(NULL,1,2,list(NULL,3,list(NULL,4)))
> str(l1)
List of 4
 $ : NULL
 $ : num 1
 $ : num 2
 $ :List of 3
  ..$ : NULL
  ..$ : num 3
  ..$ :List of 2
  .. ..$ : NULL
  .. ..$ : num 4
Run Code Online (Sandbox Code Playgroud)

要从NULL第一级删除值,只需调用即可

l1[vapply(l1,is.null,logical(1L))] <- NULL
Run Code Online (Sandbox Code Playgroud)

现在我想删除所有NULL级别的所有值,我想出了以下代码.

list.clean <- function(.data, fun = is.null, recursive = FALSE) {
  if(recursive) {
    .data <- lapply(.data, function(.item) {
      if(is.list(.item)) list.clean(.item, fun, TRUE)
      else .item
    })
  }
  .data[vapply(.data,fun,logical(1L))] <- NULL
  .data
}
Run Code Online (Sandbox Code Playgroud)

并打电话

> list.clean(l1, recursive = TRUE)
[[1]]
[1] 1

[[2]]
[1] 2

[[3]]
[[3]][[1]]
[1] 3

[[3]][[2]]
[[3]][[2]][[1]]
[1] 4
Run Code Online (Sandbox Code Playgroud)

虽然它现在可以使用,但有更好或更快的方法吗?

G. *_*eck 18

这可以递归完成:

rmNull <- function(x) {
   x <- Filter(Negate(is.null), x)
   lapply(x, function(x) if (is.list(x)) rmNull(x) else x)
}
l2 <- rmNull(l1)
Run Code Online (Sandbox Code Playgroud)

赠送:

> str(l2)
List of 3
 $ : num 1
 $ : num 2
 $ :List of 2
  ..$ : num 3
  ..$ :List of 1
  .. ..$ : num 4
Run Code Online (Sandbox Code Playgroud)

  • 您应该使用`Recall`来编写递归函数.这样,函数的名称就不会被编码到它中,如果你把它分配给其他名字,它就会破坏它.`?Recall`.除了它在*apply函数中不起作用之外,它在那里说.所以不要使用它.不要阅读此评论. (9认同)
  • 谢谢你的解决方案.但性能似乎是不可接受的:对于包含400,000个元素且最多3个级别的列表,list.clean的成本为0.18s,但rmNull在我的PC上成本为3.6s. (2认同)