【问题标题】:Why R function doesn't use variable from parent parent environment?为什么 R 函数不使用来自父父环境的变量?
【发布时间】:2018-04-14 01:53:15
【问题描述】:

我不明白,为什么glue_data 不使用父父环境中可用的变量?请参阅下面的代码。函数test_call_glue_directly 返回所需的结果。函数test_call_glue 返回错误Error in eval(x, envir = data, enclos = envir) : object 'c_1' not found

当然,我的真实函数不止一个变量。 formula_1 可能指的是 {c_2}{c_3}。或{c_456}{c_7}{c_8}c_* 的计数可能不同。

有没有办法创建专门用于调用这个glue_data的新环境?或者从父环境中提取变量?或者一些更好的方法来组织我的代码?我不想将参数c_1 传递给函数fill_1,因为在我的真实脚本中可能存在未知名称的变量数量。

fill_1 <- function(letts, n0, formula_x) {
  purrr::cross_df(list(row = n0, column = letts)) %>%
    glue::glue_data(formula_x) %>%
    matrix(ncol = length(letts)) %>%
    as.data.frame
}


test_call_glue <- function() {
  c_1 <- "C"
  formula_1 <-  "={c_1}{row}"
  fill_1(c("A"), c(1:5), formula_1)
}


test_call_glue_directly <- function() {
  # The function without wrapping glue_data in function
  c_1 <- "C"
  formula_1 <-  "={c_1}{row}"
  purrr::cross_df(list(row = c(1:5), column = c("A"))) %>%
    glue::glue_data(formula_1) %>%
    matrix(ncol = 1) %>%
    as.data.frame
}

test_call_glue_directly()
test_call_glue()

【问题讨论】:

    标签: r


    【解决方案1】:

    我回来重新审视我的问题。从那以后,我学会了使用点作为自定义函数的参数:

    fill_3a <- function(x, ...) {
      paste(paste0(x, c_1), paste0(x, c_2), sep=":::")
    }
    test_call_paste_a <- function() {
      c_1 <- "C"
      c_2 <- "H"
      ans <- fill_3a("4", c_1, c_2)
      return(ans)
    }
    
    test_call_paste_a()
    

    将未命名的参数称为我的名字可能没有意义,但对我的用例来说是有意义的,其中第一个参数是用于glue::glue 的字符串(变量按名称替换为它们的值)。

    【讨论】:

      【解决方案2】:

      看来这个可行。函数fill_1 没有找到c_1,因为它是从.GlobalEnv 调用的。您的函数是在您的环境.GlobalEnv 中创建的,这就是他们寻找变量的地方。在这里,我使用&lt;&lt;-c_1 放回.GlobalEnv

      test_call_glue <- function() {
        c_1 <- "C"
        c_1<<-c_1
        formula_1 <-  "={c_1}{row}"
        ff<-fill_1(letts=c("A"), n0=c(1:5), formula_x=formula_1)
        return(ff)
      }
      

      注意这个也可以,函数fill_1环境现在是test_call_glue(),所以它可以访问c_1

      test_call_glue <- function() {
        fill_1 <- function(letts, n0, formula_x) {
            pp<-purrr::cross_df(list(row = n0, column = letts)) %>%
              glue::glue_data(formula_x) %>%
              matrix(ncol = length(letts)) %>%
              as.data.frame
            return(pp)    
        }
        c_1 <- "C"
        formula_1 <-  "={c_1}{row}"
        ff<-fill_1(letts=c("A"), n0=c(1:5), formula_x=formula_1)
        return(ff)
      }
      

      另一种解决方案是从函数的父环境中获取 c_1。

      fill_1 <- function(letts, n0, formula_x) {
        c_1 <- get ("c_1", parent.frame())
        pp <- purrr::cross_df(list(row = n0, column = letts)) %>%
            glue::glue_data(formula_x) %>%
            matrix(ncol = length(letts)) %>%
            as.data.frame
      
        return(pp)    
      }
      

      在这里我创建了一个环境,我在其中存储变量然后检索它。我想这就是你想要的。

      envir_glue<-new.env()
      
      test_call_glue <- function() {
        c_1 <- "C"
        assign("c_1",c_1,envir=envir_glue)
        formula_1 <-  "={c_1}{row}"
        ff<-fill_1(letts=c("A"), n0=c(1:5), formula_x=formula_1)
        return(ff)
      }
      
      fill_1 <- function(letts, n0, formula_x) {
        c_1 <- get ("c_1", envir_glue)
        pp <- purrr::cross_df(list(row = n0, column = letts)) %>%
            glue::glue_data(formula_x) %>%
            matrix(ncol = length(letts)) %>%
            as.data.frame
      
        return(pp)    
      }
      

      【讨论】:

      • 这种方法有效。但是,formula_1 可能引用 {c_2} 和 {c_3}。或 {c_456}、{c_7}、{c_8}。 c_* 的计数可能不同。
      • 您的第二个代码 sn-p 确实解决了我的问题,谢谢!
      • 我仍然很想了解glue_data 指的是哪个环境。或者如何将列表传递给函数并允许使用该列表中的变量。
      • &gt; environment(fill_1) &lt;environment: R_GlobalEnv&gt; &gt; environment(test_call_glue) &lt;environment: R_GlobalEnv&gt;。我将尝试添加另一个编辑来解释如何使用环境。
      • 请注意,我尝试了类似stackoverflow.com/questions/23890522/… 的方法,但随后将 eval 设置为您的父环境,并且您看不到传递给函数的变量。所以我认为最后的解决方案是最好的
      【解决方案3】:

      感谢塞德里克!我终于明白出了什么问题。

      首先,它与胶水无关。它与其他功能相同。可选参数.env 误导了我。

      我的最终解决方案:

      fill_3 <- function(x, g) {
        attach(g)
        paste0(x, c_1)
      }
      
      test_call_paste <- function() {
        c_1 <- "C"
        c_2 <- "H"
        g_list <- list(c_1=c_1, c_2=c_2)
        ans <- fill_3("4", g_list)
        return(ans)
      }
      
      test_call_paste()
      

      这样我可以将fill 函数保持为很好的抽象,并在包装​​函数中处理实际的formula 字符串和变量。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-09-23
        • 1970-01-01
        • 2019-05-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多