为什么从Map返回的data.table会被复制?

8

我了解到data.table在从函数返回时不会被复制。然而,在这种特殊情况下,它确实被复制了。有人可以解释一下为什么吗?

dt1 <- data.table(a=1)
dt2 <- data.table(b=1)
dt3 <- data.table(c=1)

address(dt1); address(dt2); address(dt3)
[1] "000000005E20D990"
[1] "00000000052301E8"
[1] "000000001D622210"

l <- list(a=dt1, b=dt2, c=dt3)
address(l$a); address(l$b); address(l$c)
$[1] "000000005E20D990"
$[1] "00000000052301E8"
$[1] "000000001D622210"

f <- function(dt) {setnames(dt, toupper(names(dt)))}
l <- Map(f, l)
address(l$a); address(l$b); address(l$c)
$[1] "000000001945C7B0"
$[1] "0000000066858738"
$[1] "000000001B021038"

dt1
$   A
$1: 1
dt2
$   B
$1: 1
dt3
$   C
$1: 1

所以是最后一行在进行复制。但以下内容不会复制。
address(dt1)
$[1] "000000005E20D990"
dt4 <- f(dt1)
address(dt4)
$[1] "000000005E20D990"

我错过了什么?

更新 正如大家指出的那样,mapmapply会进行复制。lapply在上面的情况下可以工作,但我的实际代码需要函数中的多个输入。 我的理解是所有apply函数使用相同的代码。 但事实并非如此。


5
Map是对mapply的封装,我认为复制发生在mapply函数中。 - Roland
5
lapply的源代码中,我注意到有这样一行代码:if (MAYBE_REFERENCED(tmp)) tmp = lazy_duplicate(tmp); 而在mapply中则是if (MAYBE_REFERENCED(tmp)) tmp = duplicate(tmp);。这可能是导致问题的原因。由于我不是R内部专家,所以不能确定。 - nicola
1
如果您在父框架中有可用的对象,那么您可以轻松避免使用Mapmapply。然后使用lapply(seq_along(l), function(i) ...)并使用i迭代器对mapply中使用的对象进行子集化,因此在您的示例中为l[[i]],可能还有更多,因为mapply循环遍历多个对象。 - jangorecki
1
如果我将 l <- Map(f, l) 切换为简单的 Map(f, l),它似乎可以正常工作。你很少需要使用 set* 函数的返回值。 - Frank
2
你应该重新措辞问题,因为 funcdt<-f(dt1); address(funcdt) 显示相同的地址。换句话说,问题不在函数上,而是在 Map 上。 - Dean MacGregor
显示剩余3条评论
1个回答

0

正如众所周知的那样,使用Mapmapply会进行复制操作。


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