在within()中删除多个命名列表组件

mar*_*tin 5 null r list with-statement named

我试图从列表中删除命名组件,使用withinrm.这适用于单个组件,但不适用于两个或更多组件.我完全糊涂了.

例如 - 这是有效的

aa = list(a = 1:3, b = 2:5, cc = 1:5)
within(aa, {rm(a)})
Run Code Online (Sandbox Code Playgroud)

输出within将只包含未删除的组件.

但是,这不是:

aa = list(a = 1:3, b = 2:5, cc = 1:5)
within(aa, {rm(a); rm(b)})
Run Code Online (Sandbox Code Playgroud)

这也不是:

within(aa, {rm(a, b)})
Run Code Online (Sandbox Code Playgroud)

输出within将包含所有组件,以及我要删除的组件,设置为NULL.为什么?

Cam*_*nek 4

首先,请注意以下行为:

> 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
Run Code Online (Sandbox Code Playgroud)

现在让我们看一下代码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
}
Run Code Online (Sandbox Code Playgroud)

特别查看该函数的倒数第二行。如果列表中已删除项目的数量大于 1,则该函数本质上是调用aa[c('a', 'b')] <- list(NULL, NULL),因为vector("list", 2)创建一个包含两项的列表,其中每个项目都是NULL。我们可以创建自己的版本,从函数的第二行到最后一行within删除语句:else

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
}
Run Code Online (Sandbox Code Playgroud)

现在我们来测试一下:

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

现在它按预期工作了!