2015-11-25 20 views
5

Ich versuche, eine benannte Komponente aus einer Liste zu entfernen, mit within und rm. Dies funktioniert für eine einzelne Komponente, aber nicht für zwei oder mehr. Ich bin völlig verwirrt.Entfernen mehrerer Named-List-Komponenten innerhalb()

Zum Beispiel - das funktioniert

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

die Ausgabe von within haben die nicht entfernten Komponenten einfach.

Allerdings bedeutet dies nicht:

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

Weder tut dies:

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

Die Ausgabe von within wird alle Komponenten, mit denen ich entfernen versuchen, auf NULL . Warum?

+0

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

+0

Nun, ja. Aber ich versuche es innerhalb von – martin

+0

zu tun. Das ist komisches Verhalten! Sie können einen löschen, aber danach bleiben sie als NULL - auch wenn es mehr als 3 Spalten gibt. Funktioniert ähnlich mit 'innerhalb (aa, {" b "<- NULL;" a "<- NULL})' – jeremycg

Antwort

4

Zunächst beachten Sie folgendes Verhalten:

> 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 

nun auf den Code für within.list aussehen lassen:

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 
} 

Blick insbesondere auf der vorletzten Zeile der Funktion. Wenn die Anzahl gelöschter Elemente in der Liste größer als eins ist, ruft die Funktion im Wesentlichen aa[c('a', 'b')] <- list(NULL, NULL) auf, weil vector("list", 2) eine Liste mit zwei Elementen erstellt, wobei jedes Element NULL ist. Wir können unsere eigene Version von within schaffen, in dem wir die else Aussage von der zweiten zur letzten Zeile der Funktion entfernen:

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 
} 

Nun wollen wir es testen:

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

Jetzt funktioniert es wie erwartet!

+0

Ah, ja. Hätte gedacht, auf die Quelle zu schauen. Sehr dankbar! – martin

+0

Das ist sehr ordentlich, aber warum müssen Sie die else-Klausel von 'in.list' entfernen? und angenommen, es ist ein Fehler, bitte einen R-Fehler auf "base :: in" ablegen – smci