2015-11-25 13 views
5

Sto tentando di rimuovere un componente con nome da un elenco, utilizzando within e rm. Funziona per un singolo componente, ma non per due o più. Sono completamente confuso.Rimozione di più componenti dell'elenco con nome in()

Per esempio - questo funziona

aa = list(a = 1:3, b = 2:5, cc = 1:5) 
within(aa, {rm(a)}) 

l'uscita dal within avrà solo i componenti non rimossi.

Tuttavia, questo non:

aa = list(a = 1:3, b = 2:5, cc = 1:5) 
within(aa, {rm(a); rm(b)}) 

Né fa questo:

within(aa, {rm(a, b)}) 

L'uscita dal within avrà tutte le componenti, con quelli che sto cercando di rimuovere, insieme a NULL . Perché?

+0

'aa ['a'] <- NULL'? – etienne

+0

Beh, sì. Ma sto cercando di farlo all'interno di – martin

+0

Questo è un comportamento strano! puoi eliminarne uno, ma dopo rimangono come NULL - anche se ci sono più di 3 colonne. Funziona in modo simile a 'within (aa, {" b "<- NULL;" a "<- NULL})' – jeremycg

risposta

4

In primo luogo, si noti il ​​seguente comportamento:

> aa = list(a = 1:3, b = 2:5, cc = 1:5) 
> 
> aa[c('a', 'b')] <- NULL 
> 
> aa 
# $cc 
# [1] 1 2 3 4 5 

> aa = list(a = 1:3, b = 2:5, cc = 1:5) 
> 
> aa[c('a', 'b')] <- list(NULL, NULL) 
> 
> aa 
# $a 
# NULL 
# 
# $b 
# NULL 
# 
# $cc 
# [1] 1 2 3 4 5 

Ora diamo un'occhiata al codice per within.list:

within.list <- function (data, expr, ...) 
{ 
    parent <- parent.frame() 
    e <- evalq(environment(), data, parent) 
    eval(substitute(expr), e) 
    l <- as.list(e) 
    l <- l[!sapply(l, is.null)] 
    nD <- length(del <- setdiff(names(data), (nl <- names(l)))) 
    data[nl] <- l 
    if (nD) 
     data[del] <- if (nD == 1) NULL else vector("list", nD) 
    data 
} 

Cerca in particolare in occasione della penultima riga della funzione. Se il numero di elementi eliminati nell'elenco è maggiore di uno, la funzione chiama essenzialmente aa[c('a', 'b')] <- list(NULL, NULL), poiché vector("list", 2) crea un elenco di due elementi in cui ogni elemento è NULL. Siamo in grado di creare la nostra versione di within dove abbiamo rimuovere l'istruzione else dalla seconda all'ultima riga della funzione:

mywithin <- function (data, expr, ...) 
{ 
    parent <- parent.frame() 
    e <- evalq(environment(), data, parent) 
    eval(substitute(expr), e) 
    l <- as.list(e) 
    l <- l[!sapply(l, is.null)] 
    nD <- length(del <- setdiff(names(data), (nl <- names(l)))) 
    data[nl] <- l 
    if (nD) data[del] <- NULL 
    data 
} 

Ora Testiamola:

> aa = list(a = 1:3, b = 2:5, cc = 1:5) 
> 
> mywithin(aa, rm(a, b)) 
# $cc 
# [1] 1 2 3 4 5 

Ora funziona come previsto!

+0

Ah, sì. Dovrebbe aver pensato di guardare la fonte. Molto apprezzato! – martin

+0

Questo è molto bello, ma perché è necessario rimuovere la clausola else da 'within.list'? e supponendo che sia un bug, si prega di presentare un bug R su 'base :: within' – smci