删除NULL元素并从R中的嵌套列表中取消列出本地级别列表

时间:2014-06-20 15:07:20

标签: r

假设我有一个列表,说它有三个级别:

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元素的列表。 谢谢!

3 个答案:

答案 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。所以让我们从一个更复杂的例子开始:

enter image description here

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