【问题标题】:Why is r not modifying in place in this situation?为什么 r 在这种情况下没有就地修改?
【发布时间】:2020-03-14 23:54:21
【问题描述】:
> z <- 1:10
> lobstr::obj_addr(z)
[1] "0x564d8d9eaac8"

> z[[3]] <- 4L
> lobstr::obj_addr(z)
[1] "0x564d882b4328"

为什么修改后地址不一样了? 这应该是原地修改吧?

【问题讨论】:

  • @akrun lobstr 是包名
  • @user20650 是的,这有关系吗?
  • 高级 R 中的以下章节对此很有帮助。 2.3 修改时复制 Wickham, Hadley。 Advanced R,第二版(Chapman & Hall/CRC The R Series)(第 22 页)。 CRC出版社。 Kindle 版。
  • 我假设您在 Rstudio 中运行它? IDE 保留对要在环境窗口中显示的对象的引用,这会干扰就地修改。如果您在标准 R GUI 中运行它,您会看到地址是相同的。

标签: r


【解决方案1】:

较早的问题(例如here)解释了 R 何时执行复制的一些方面。但是,在 OP 的示例中还有一个额外的细微差别值得在这里强调。请注意,以下代码已在 R 控制台中执行,而不是在 RStudio 中。正如其他人 previously 指出的那样,Rstudio 对流程有其自身的影响,我们在此通过直接在 R 中工作来消除这些影响。

R 的“修改行为复制”可能很复杂。 R 将尝试在适当的位置进行替换,尽可能。但是,有一个有趣的原因是,这不是它可以这样做的情况之一。这与自 R 3.5.0 以来引入的“AltRep”(替代表示)优化有关。一种这样的优化是能够仅使用它们的末端成员来存储连续的数字序列,而不是分配整个向量。详情请见here

让我们尝试看看在这种情况下发生了什么,使用.Internal(inspect(z)) 来窥探对象表示的内部结构,并使用tracemem 来检测对象何时被复制:

x = 1L:10L
tracemem(x)
# [1] "<0x559377dba830>"
.Internal(inspect(x))
# @559377dba830 13 INTSXP g0c0 [NAM(7),TR]  1 : 10 (compact)

正如我们所见,在这个阶段,1:10 以 1:10(紧凑)的形式表示。这意味着尚未明确评估或分配完整序列。目前仅存在其开始值和结束值的紧凑表示..

现在,当我们分配给向量的一个元素时,我们看到该对象确实被复制了:

x[[3]] = 4L
# tracemem[0x559377dba830 -> 0x559376ae1e48]: 

我们还可以看到,对象的内部结构也变成了一个明确的整数向量,而不是 1:10 的“紧凑”形式:

.Internal(inspect(x))
# @559376ae1e48 13 INTSXP g0c4 [NAM(1),TR] (len=10, tl=0) 1,2,4,4,5,...

现在,将其与以下版本进行比较,在该版本中, 不会触发副本(因为初始向量已经处于展开(非紧凑)形式):

x = c(1L:10L)
tracemem(x)
# [1] "<0x55d6146772d8>"
.Internal(inspect(x))
# @55d6146772d8 13 INTSXP g0c4 [NAM(1),TR] (len=10, tl=0) 1,2,3,4,5,...

x[[3]] = 4L
# No copying occured here!!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-04-21
    • 1970-01-01
    • 1970-01-01
    • 2016-05-12
    • 1970-01-01
    • 2013-04-23
    • 1970-01-01
    相关资源
    最近更新 更多