【发布时间】:2021-04-22 00:32:10
【问题描述】:
当我将 data.table 作为参数传递给函数时,我可以在被调用函数中“通过引用”更新该表,并将结果应用于原始对象。 但是,如果我做一些需要“深拷贝”的事情(例如 rbindlist 添加行),则该副本仅存在于被调用的函数中。原始对象在调用框架中保持不变。
library(data.table)
l1 <- function(a1, action='update'){
b <- l2(a1, action)
print('l1')
print(a1)
}
l2 <- function(a2, action){
c <- l3(a2, action)
print('l2')
print(a2)
}
l3 <- function(a3, action){
if (action == 'update') a3[, col2 := col + 1]
if (action == 'append') a3 <- rbindlist(list(a3, data.table(col = c(21, 22))), fill=TRUE)
if (action == 'forceupdate') assign('DT',
rbindlist(list(a3, data.table(col = c(21, 22))), fill=TRUE),
envir = parent.frame(3))
print('l3')
print(a3)
a3
}
DT <- data.table(col = c(1, 2, 3))
print(DT)
#> col
#> 1: 1
#> 2: 2
#> 3: 3
l1(DT, 'update')
#> [1] "l3"
#> col col2
#> 1: 1 2
#> 2: 2 3
#> 3: 3 4
#> [1] "l2"
#> col col2
#> 1: 1 2
#> 2: 2 3
#> 3: 3 4
#> [1] "l1"
#> col col2
#> 1: 1 2
#> 2: 2 3
#> 3: 3 4
print(DT)
#> col col2
#> 1: 1 2
#> 2: 2 3
#> 3: 3 4
l1(DT, 'append')
#> [1] "l3"
#> col col2
#> 1: 1 2
#> 2: 2 3
#> 3: 3 4
#> 4: 21 NA
#> 5: 22 NA
#> [1] "l2"
#> col col2
#> 1: 1 2
#> 2: 2 3
#> 3: 3 4
#> [1] "l1"
#> col col2
#> 1: 1 2
#> 2: 2 3
#> 3: 3 4
print(DT)
#> col col2
#> 1: 1 2
#> 2: 2 3
#> 3: 3 4
l1(DT, 'forceupdate')
#> [1] "l3"
#> col col2
#> 1: 1 2
#> 2: 2 3
#> 3: 3 4
#> [1] "l2"
#> col col2
#> 1: 1 2
#> 2: 2 3
#> 3: 3 4
#> [1] "l1"
#> col col2
#> 1: 1 2
#> 2: 2 3
#> 3: 3 4
print(DT)
#> col col2
#> 1: 1 2
#> 2: 2 3
#> 3: 3 4
#> 4: 21 NA
#> 5: 22 NA
由reprex package (v1.0.0) 于 2021 年 4 月 22 日创建
在此示例中,有一个 3 级的函数调用堆栈。第一级的参数向下传递堆栈并在函数 l3 中更新。
使用 data.table 更新语法,l3 向对象添加一个新列,这导致原始对象被“就地”更改,结果在调用堆栈的每个级别中都可以看到。
但是,如果我使用 rbindlist 添加行,则会在 l3 的框架内进行复制,这不会影响原始对象或父调用中的任何视图。
如果我将更改分配回“原始框架”,那么它会在那里看到,但中间调用看不到更改。
有没有办法将这个“深拷贝”的结果反映到调用堆栈上?
如果assign 是要走的路,我会很感激一个例子,说明如何建立底层数据对象的名称和环境,以便无需硬编码即可进行此分配。
【问题讨论】:
-
如果你总是想用
deep copy,那么就用copy(dt)吧。 -
谢谢和平。然而,这里的问题是深拷贝的影响以及结果表最终所在的框架/环境。如果复制是在本地完成的,则调用函数无法看到结果,如果将其分配回原始帧,则中间函数无法看到结果。我希望它的行为与引用更新一样。
-
在我需要向 data.table 添加行的情况下,我也遇到了这个问题,所以如果出现聪明的答案,我很感兴趣。目前,在这种情况下,我有时会选择
<<-,它会逐步向上搜索到父环境,直到它到达将创建某些东西的全局。它不完美,但可以满足您的需求。
标签: r data.table pass-by-reference