假设我有一个列表,说它有三个级别:
tmp =list(list(list(c(2,9,10), NULL), c(1,3,4,6)), 7)
这将输出
[[1]]
[[1]][[1]]
[[1]][[1]][[1]]
[1] 2 9 10
[[1]][[1]][[2]]
NULL
[[1]][[2]]
[1] 1 3 4 6
[[2]]
[1] 7
我想删除NULL元素和列表的本地级别。即,嵌套列表tmp只有2个级别,它变为
tmp =list(list(c(2,9,10), c(1,3,4,6)), 7).
也就是说,所需的输出可能如下:
tmp
[[1]]
[[1]][[1]]
[1] 2 9 10
[[1]][[2]]
[1] 1 3 4 6
[[2]]
[1] 7
我试图搜索NULL的索引位置,但没有运气。此外,我不知道如何检测和取消列表列表中包含NULL元素的列表。 谢谢!
答案 0 :(得分:14)
通常,您使用
删除平面列表中的NULL
元素
ll <- list( 1, 2, NULL, 3 )
ll <- ll[ ! sapply(ll, is.null) ]
如果您事先不知道结构,那么将此解决方案与递归函数结合起来就是一个明显的例子:
removeNullRec <- function( x ){
x <- x[ !sapply( x, is.null ) ]
if( is.list(x) ){
x <- lapply( x, removeNullRec)
}
return(x)
}
removeNullRec(tmp)
[[1]]
[[1]][[1]]
[[1]][[1]][[1]]
[1] 2 9 10
[[1]][[2]]
[1] 1 3 4 6
[[2]]
[1] 7
修改强>
尽可能简单地重新解决问题总是好的。我从你的评论中理解的是,(与NULL
元素的出现无关)你想要替换孩子本身只包含一个孩子的每个元素。还有另一个案例需要考虑:两个兄弟叶子也可以NULL
。所以让我们从一个更复杂的例子开始:
tree <- list(
list(
list(
list(
list( NULL, NULL ),
list( NULL, NULL )
),
7
),
list(
list(
list( c(1,2), NULL ),
c(3,4)
))))
通过应用递归方法,当然也解决了使树平坦化的这个孤立问题:
flatTreeRec <- function( x ){
if( is.list(x) ){
# recursion
x <- lapply( x, flatTree )
# remove empty branches
x <- x[ sapply( x, length ) > 0 ]
# flat branches with only child
if( length(x) == 1 ){
x <- x[[1]]
}
}
return(x)
}
flatTreeRec( removeNullRec(tree) )
当然,您可以直接将这两个函数组合在一起,以避免对堆栈施加两次压力:
removeNullAndFlatTreeRec <- function( x ){
x <- x[ !sapply( x, is.null ) ]
if( is.list(x) ){
x <- lapply( x, removeNullRec)
x <- x[ sapply( x, length ) > 0 ]
if( length(x) == 1 ){
x <- x[[1]]
}
}
return(x)
}
removeNullAndFlatTreeRec( tree )
答案 1 :(得分:0)
我正在使用此功能:
removeNULL <- function(x){
x <- Filter(Negate(is.null), x)
if( is.list(x) ){
x <- lapply( x, function(y) Filter(length, removeNULL(y)))
}
return(x)
}
不仅删除了NULL
元素,还删除了仅包含NULL
元素的列表元素,例如下面示例中的A2$A2$format$font
:
> A2
$A2
$A2$value
[1] 9.9
$A2$format
$A2$format$numberFormat
[1] "2Decimal"
$A2$format$font
$A2$format$font$name
NULL
$A2$format$font$bold
NULL
$A2$format$font$color
NULL
$A2$comment
NULL
> removeNULL(A2)
$A2
$A2$value
[1] 9.9
$A2$format
$A2$format$numberFormat
[1] "2Decimal"
答案 2 :(得分:0)
更新2020年6月:现在也可以使用rrapply
软件包中的rrapply
(基础rrapply
的修订版)来完成此操作。使用how = "prune"
,我们可以修剪列表中的所有NULL
元素,同时保留原始列表结构。例如,使用与Beasterfield响应中相同的列表对象:
library(rrapply)
## Example 1
tmp <- list(list(list(c(2,9,10), NULL), c(1,3,4,6)), 7)
## keep only non-NULL leafs
rrapply(tmp, condition = Negate(is.null), how = "prune")
#> [[1]]
#> [[1]][[1]]
#> [[1]][[1]][[1]]
#> [1] 2 9 10
#>
#>
#> [[1]][[2]]
#> [1] 1 3 4 6
#>
#>
#> [[2]]
#> [1] 7
## Example 2
tree <- list(
list(
list(
list(
list( NULL, NULL ),
list( NULL, NULL )
),
7
),
list(
list(
list( c(1,2), NULL ),
c(3,4)
))))
## branches with only NULLs are completely pruned
rrapply(tree, condition = Negate(is.null), how = "prune")
#> [[1]]
#> [[1]][[1]]
#> [[1]][[1]][[1]]
#> [1] 7
#>
#>
#> [[1]][[2]]
#> [[1]][[2]][[1]]
#> [[1]][[2]][[1]][[1]]
#> [[1]][[2]][[1]][[1]][[1]]
#> [1] 1 2
#>
#>
#> [[1]][[2]][[1]][[2]]
#> [1] 3 4