2014-06-20 7 views
7

Supponiamo che ho una lista, dicono che ha tre livelli:Rimuovere elemento NULL e non elencati nella lista livello locale da un elenco nidificato in R

tmp =list(list(list(c(2,9,10), NULL), c(1,3,4,6)), 7) 

Questo sarebbe uscita

[[1]] 
[[1]][[1]] 
[[1]][[1]][[1]] 
[1] 2 9 10 

[[1]][[1]][[2]] 
NULL 

[[1]][[2]] 
[1] 1 3 4 6 

[[2]] 
[1] 7 

vorrei rimuovere l'elemento NULL e il livello locale dell'elenco. cioè, l'elenco tmp annidata ha solo 2 piani e diventa

tmp =list(list(c(2,9,10), c(1,3,4,6)), 7). 

Cioè, l'uscita desiderata potrebbe essere sia il seguente:

tmp 
[[1]] 
[[1]][[1]] 
[1] 2 9 10 

[[1]][[2]] 
[1] 1 3 4 6 

[[2]] 
[1] 7 

ho provato a cercare la posizione di indice NULL ma senza fortuna. Inoltre, non sono sicuro di come rilevare e non elencare l'elenco che contiene l'elemento NULL all'interno dell'elenco. Grazie!

risposta

13

In genere, si rimuove NULL elementi su una semplice lista con

ll <- list(1, 2, NULL, 3) 
ll <- ll[ ! sapply(ll, is.null) ] 

Se non si conosce la struttura in anticipo, questo è un chiaro caso di combinare questa soluzione con una funzione ricorsiva:

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 

Modifica

E 'sempre bene di riformulare il problema il più semplice possibile. Quello che ho capito dai tuoi commenti è che (indipendentemente dall'occorrenza degli elementi NULL) che vuoi sostituire ogni elemento che contiene solo un figlio dal bambino stesso. C'è anche un altro caso che deve essere considerato allora: due foglie di pari livello potrebbero essere NULL pure. Quindi, consente di iniziare con un po 'esempio più complesso:

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) 
)))) 

Questo problema isolato al piatto l'albero è, naturalmente, anche risolti meglio applicando approccio ricorsivo:

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)) 

E Ovviamente puoi combinare direttamente queste due funzioni per evitare di stressare lo stack due volte:

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) 
+0

Grazie mille! Mi chiedevo se la lista che contiene l'elemento NULL potesse essere non elencata dall'elenco annidato. Per il mio esempio precedente, se un elemento NULL viene rilevato nell'elenco, quindi non elenco l'elenco, in modo che l'elenco nidificato ha solo 2 elenchi. cioè, lista (lista (c (2,9,10), c (1,3,4,6)), 7). La tua funzione conserva lo stesso numero di liste presenti nell'elenco originale. – user2498497

+0

Grazie!Il tuo codice funziona nella rimozione dell'elemento NULL. Tuttavia non rimuove/non elenca l'elenco che contiene l'elemento NULL. – user2498497

+0

@ user2498497 in quali casi vuoi escludere dalla lista i fratelli dell'elemento 'NULL'? Solo se è l'unico fratello ed è piatto (cioè non contiene bambini)? E i casi in cui un elemento della lista è l'unico elemento nella gerarchia ed è piatto. Vuoi che non siano in elenco anche se non esiste un fratello 'NULL'? Quale dovrebbe essere il risultato corretto di 'lista (lista (lista (1,2,3), NULL))'? – Beasterfield

0

sto usando questa funzione:

removeNULL <- function(x){ 
    x <- Filter(Negate(is.null), x) 
    if(is.list(x)){ 
     x <- lapply(x, function(y) Filter(length, removeNULL(y))) 
    } 
    return(x) 
} 

Non solo rimuovere le NULL elementi, ma rimuove anche gli elementi che sono un elenco contenente solo NULL elementi, come A2$A2$format$font nel seguente esempio:

> 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" 
Problemi correlati