代码之家  ›  专栏  ›  技术社区  ›  Manuel R

在R中计算一个值,给定一个承诺的名称或形式参数

  •  0
  • Manuel R  · 技术社区  · 7 年前

    代码:

    args <- function() {
      list(
        x = "How old",
        y = "is",
        z = "the car?")
    }
    
    fun1 <- function(x = "How old", y = "is", z = "the car") {
      # collect arguments
      args_used   <- as.list(match.call()[-1])
    
      # Call fun2() using the args supplied by the user
      do.call(fun2, args_used)
    
    }
    
    fun2 <- function(x = args()$x, y = args()$y, z = args()$z) {
      paste(x, y, z)
    }
    

    问题

    使用 fun1() 和/或 fun2() 如果直接使用,请尝试例如。,

    > fun1("Where", "are", z = "the cars")
    [1] "Where are the cars"
    

    但是,如果我这样做了:

    list1 <- list(l1 = "Where", l2 = "Is this")
    list2 <- list(l1 = "is", l2 = "the")
    list3 <- list(l1 = "Peter", l2 = "new iPhone?")
    
    mapply(function(i, j, k) fun1(x = i, y = j, z = k),
           i = list1,
           j = list2,
           k = list3,
           SIMPLIFY = FALSE)
    

    我明白了

    Error in paste(x, y, z) : object 'i' not found

    我知道 为什么? 问题发生了,我甚至知道如何用 eval(parse(text = "")) (尽管我知道eval parse策略的潜在问题(参见,例如: this discussion )

    因此重写 功能1() 这样地:

    fun1 <- function(x = "How old", y = "is", z = "the car") {
      # collect arguments
      args_used <- as.list(match.call()[-1])
      args_used <- lapply(names(args_used), function(w) eval(parse(text = w))) 
    
      # Call fun2() using the args supplied by the user
      do.call(fun2, args_used)
    
    }
    

    并随后使用 mapply(....) 如上所述。

    但是在这里它变得棘手。

    1. 注意如果我改变会发生什么 w 在里面 lapply(names(args_used), function(w) eval(parse(text = w))) x (同样适用于 y z . 正在呼叫 mapply 如上所述,给出:
      $`l1`
      [1] "x is Peter"
      
      $l2
      [1] "x the new iPhone?"
      

      显然不是我想要的。我再一次明白了为什么会发生这种情况,解决方法是不使用 但是有点像 西 但任何一个名字从现在起都是保留的。不太理想。

    2. 如果通过 ... 争论。修改 功能1() 这样地:

      fun1 <- function(x = "How old", y = "is", ...) {
        # collect arguments
        args_used <- as.list(match.call()[-1])
        args_used <- lapply(names(args_used), function(x) eval(parse(text = x))) 
      
        # Call fun2() using the args supplied by the user
        do.call(fun2, args_used)
      
      }
      

      现在的结果是

      Error in eval(parse(text = x)) : object 'z' not found

    再说一遍,我明白为什么(因为名字 "z" 是未知的 功能1() 但现在的问题是:

    如何解决这个问题,避免问题1和问题2?

    1 回复  |  直到 7 年前
        1
  •  1
  •   MrFlick    7 年前

    只需让您的函数在调用环境中计算参数。这似乎有效(注意 envir=parent.frame() ).

    fun1 <- function(x = "How old", y = "is", z = "the car") {
      args_used  <- as.list(match.call()[-1])
      do.call(fun2, args_used, envir=parent.frame()) 
    }
    

    但我不明白你为什么在这里使用惰性评估。您只需捕获作为环境一部分的所有片段并传递它们的值

    fun1 <- function(x = "How old", y = "is", z = "the car") {
      args_used  <- as.list(environment())
      # if you need ...: args_used <- c(as.list(environment()), list(...))
      do.call(fun2, args_used) 
    }
    

    请注意 environment() 将捕获在调用时存在的所有变量。因此,如果您只希望将变量传递给函数,请确保在函数的开头调用它。

    如果参数的名称中有前导点,R通常将其视为“隐藏”,因此需要设置 all.names=TRUE 参数到 as.list.environment 函数来获取它们。你可以的

    args_used  <- as.list(environment(), all.names=TRUE)