Remove NULL element and unlist the local level list from a nested list in R
I'm using this function:
removeNULL <- function(x){
x <- Filter(Negate(is.null), x)
if( is.list(x) ){
x <- lapply( x, function(y) Filter(length, removeNULL(y)))
}
return(x)
}
Not only it remove the NULL
elements, but it also removes the elements which are a list containing only NULL
elements, such as A2$A2$format$font
in the example below:
> 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"
Typically, you remove NULL
elements on a flat list with
ll <- list( 1, 2, NULL, 3 )
ll <- ll[ ! sapply(ll, is.null) ]
If you do not know the structure in advance, this is a clear case to combine this solution with a recursive function:
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
Edit
It's always good to rephrase the problem as simple as possible. What I understood from your comments is, that (independent of the occurrence of NULL
elements) you want to replace each element which contains only one child by the child itself. There is also another case which has to be considered then: Two sibling leafs could be NULL
as well. So lets start with a little bit more complicated example:
tree <- list(
list(
list(
list(
list( NULL, NULL ),
list( NULL, NULL )
),
7
),
list(
list(
list( c(1,2), NULL ),
c(3,4)
))))
This isolated problem to flat the tree is of course also solved best by applying recursive approach:
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) )
And of course you can directly combine this two functions to avoid stressing your stack twice:
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 )