How to Manipulate Null Elements in a Nested List

How to manipulate NULL elements in a nested list?

I'm going to go with "use a version of rapply doesn't doesn't have weird behaviour with NULL". This is the simplest implementation I can think of:

simple_rapply <- function(x, fn)
{
if(is.list(x))
{
lapply(x, simple_rapply, fn)
} else
{
fn(x)
}
}

(rawr::rapply2, as mentioned in the comments by @rawr is a more sophisticated attempt.)

Now I can do the replacement using

simple_rapply(l, function(x) if(is.null(x)) NA else x)

Remove NULL element and unlist the local level list from a nested list in R

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:

Sample Image

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 )

Using values in nested lists with NULL-values as an if-condition R

Here is a vectorized way of replacing the strings in data$text by new values, depending on the url's values being not NULL.

Note that entities$urls must be changed to data$entities$urls

i_not_null <- which(!sapply(entities$urls, is.null))
displ_url <- sapply(entities$urls[i_not_null], `[[`, 'display_url')
i_text <- i_not_null * grepl("^pic.*\\s*", displ_url)
i_text <- i_text[i_text != 0]

data$text[i_text] <- gsub("http.*\\s*", "", data$text[i_text])

Python: How to initialize a nested list with empty values which i can append to

Try using a list comprehension within a list comprehension:

>>> [ [ [] for i in range(wid) ] for i in range(hgt) ]
[[[], [], []], [[], [], []], [[], [], []]]

Note this is preferred to list multiplication because each of these lists is unique. Compare:

>>> x = [ [[] for i in range(wid)] for i in range(hgt) ]
>>> x[1][1].append('a')
>>> x
[[[], [], []], [[], ['a'], []], [[], [], []]]

vs.

>>> y = [ [[]] * wid for i in range(hgt) ]
>>> y[1][1].append('a')
>>> y
[[[], [], []], [['a'], ['a'], ['a']], [[], [], []]]

vs.

>>> z = [ [[]] * wid ] * hgt
>>> z[1][1].append('a')
>>> z
[[['a'], ['a'], ['a']], [['a'], ['a'], ['a']], [['a'], ['a'], ['a']]]

Where, in the second and third cases, 'a' appears in multiple cells! And using None does not avoid this problem:

>>> m = [ [None] * wid ] * hgt
>>> m
[[None, None, None], [None, None, None], [None, None, None]]
>>> if m[1][1] is None:
... m[1][1] = ['a']
... else:
... m[1][1].append('a')
...
>>> m
[[None, ['a'], None], [None, ['a'], None], [None, ['a'], None]]

tl;dr - use the double list comprehension. In my opinion, it's the most readable option anyway.

Remove empty nested lists - Python

I think what you want to do is

tscores = [x for x in tscores if x != []]

which make a list of only the none empty lists in tscores



Related Topics



Leave a reply



Submit