rapply和lapply为什么处理NULL的方式不同?

16

我知道列表中的空值有时可能会使人们困惑。我想知道为什么在特定情况下,lapplyrapply似乎会以不同的方式处理NULL值。

l <- list(a = 1, c = NULL, d = 3)

lapply(l,is.null)
$a
[1] FALSE

$c
[1] TRUE

$d
[1] FALSE

到目前为止还不错。我们尝试使用rapply做完全相同的事情会怎么样呢?

rapply(l, is.null, how = "replace")
$a
[1] FALSE

$c
list()

$d
[1] FALSE

这个例子非常简单且不涉及递归,但是您可以在嵌套列表中使用rapply看到相同的行为。

我的问题是为什么?如果像?rapply中所宣传的那样,它是lapply的递归版本,为什么在这种情况下它们的行为会如此不同?

1个回答

21

我认为你自己回答了这个问题:因为它是递归的。

这种情况并不常见,但实际上可以使用NULL来表示空序列,因为它是空的pairlist(类似于Scheme中()终止列表的方式。在内部,R非常类似于Scheme)。

因此,rapply对空列表进行递归处理,但在完成后不会费心将其转换回pairlist;您会得到一个常规的空列表。

实际上,rapplylapply并没有真正不同地处理NULL:

> lapply(NULL, identity)
list()

您可以在 R 源代码(memory.c)中看到,这正是 pairlists 的工作原理:

SEXP allocList(int n)
{
    int i;
    SEXP result;
    result = R_NilValue;
    for (i = 0; i < n; i++)
        result = CONS(R_NilValue, result);
    return result;
}

1
+1 指出 NULL 是一个空的 pairlist。所以你的意思是说 rapply 不能(或不会)区分 NULLpairlist() - joran
1
@joran identical(pairlist(), NULL) :) 的意思是完全相同的(pairlist()和NULL)。 :) - Owen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接