First, pay attention to the following behavior:
> 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
Now look at the code for 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 }
Look, in particular, at the second in the last line of the function. If the number of deleted items in the list is greater than one, the function essentially calls aa[c('a', 'b')] <- list(NULL, NULL) , because vector("list", 2) creates a list of two items, each element of which is NULL . We can create our own version of within , where we remove the else from the second to the last line of the function:
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 }
Now let's test it:
> aa = list(a = 1:3, b = 2:5, cc = 1:5) > > mywithin(aa, rm(a, b))
Now it works as expected!