In R, how can I check if two variable names reference the same underlying object?

前端 未结 3 925
抹茶落季
抹茶落季 2020-12-03 07:26

For example:

A <- 1:10
B <- A

Both A and B reference the same underlying vector.

Before I plow off and implement something in

相关标签:
3条回答
  • 2020-12-03 07:59

    You can use the .Internal inspect function:

    A <- 1:10
    B <- A
    .Internal(inspect(A))
    # @27c0cc8 13 INTSXP g0c4 [NAM(2)] (len=10, tl=0) 1,2,3,4,5,...
    .Internal(inspect(B))  # same
    # @27c0cc8 13 INTSXP g0c4 [NAM(2)] (len=10, tl=0) 1,2,3,4,5,...
    B[1] <- 21
    .Internal(inspect(B))  # different
    # @25a7528 14 REALSXP g0c6 [NAM(1)] (len=10, tl=150994944) 21,2,3,4,5,...
    

    Simon Urbanek has written a simple package with similar functionality. It's called... wait for it... inspect. You can get it from R-forge.net by running:

    install.packages('inspect',repos='http://www.rforge.net/')
    

    UPDATE: A word of warning:

    I recommend you use Simon's package because I'm not going to recommend you call .Internal. It certainly isn't intended to be used interactively and it may very well be possible to crash your R session by using it carelessly.

    0 讨论(0)
  • 2020-12-03 08:15

    I found this question when looking for a function that checks whether a single variable is referenced at all, especially in the context of data.table. Extending the other answers, I believe the following function does this:

    is_referenced <- function(x) {
      nom <- as.character(substitute(x))
      ls_ <- ls(parent.frame())
      ls_ <- ls_[ls_ != nom]
      tr <- tracemem(x)
      for (i in ls_) {
        if (identical(x, get(i, envir = parent.frame()))) {
          if (identical(tr, tracemem(get(i, envir = parent.frame())))) {
            untracemem(x)
            untracemem(get(i, envir = parent.frame()))
            print(i)
            return(TRUE)
          } else {
            untracemem(get(i, envir = parent.frame()))
          }
        }
      }
      untracemem(x)
      FALSE
    } 
    
    x <- 1:10
    y <- x
    is_referenced(x)
    #> [1] "y"
    #> [1] TRUE
    
    z <- 1:10
    is_referenced(z)
    #> [1] FALSE
    
    y[1] <- 1L
    is_referenced(y)
    #> [1] FALSE
    
    
    library(data.table)
    DT <- data.table(x = 1)
    ET <- DT
    is_referenced(DT)
    #> [1] "ET"
    #> [1] TRUE
    is_referenced(ET)
    #> [1] "DT"
    #> [1] TRUE
    
    ET[, y := 1]
    is_referenced(DT)
    #> [1] "ET"
    #> [1] TRUE
    
    DT <- copy(ET)
    is_referenced(DT)
    #> [1] FALSE
    

    Created on 2018-08-07 by the reprex package (v0.2.0).

    0 讨论(0)
  • 2020-12-03 08:18

    You can get at this via tracemem: if these are pointing to the same memory location, they are the same memory objects.

    > a = 1:10
    > b = a
    > tracemem(a)
    [1] "<0x00000000083885e8"
    > tracemem(b)
    [1] "<0x00000000083885e8"
    > b = 1:10
    > tracemem(b)
    [1] "<0x00000000082691d0"
    > 
    

    As for why it is very useful to know if they are the same objects: if they are pointing to the same object and there's a delayed evaluation / lazy evaluation / promise then if one object changes, calculations will be suspended while a new block of memory is assigned. In some contexts the delay can be substantial. If there are large objects, then the wait is long while a big block of memory is allocated and copied. Other times it could just be a death by a thousand cuts: lots of little perturbations and delays here and there.

    Update (Incorporating Joshua's comment): Be sure to use untracemem(), lest you get lots of output. You can also look at retracemem, though I can't yet comment on its utility for setting the trace.

    0 讨论(0)
提交回复
热议问题