30

是否可以从...中删除一个元素并将...传递给其他功能?我的前两次尝试失败了:

parent = function(...)
{

   a = list(...)
   str(a)
   a$toRemove = NULL  
   str(a)

   # attempt 1   
   child(a)   

   # attempt 2
   child( ... = a )
}


child = function(...)
{
  a = list( ... )
  str(a)
}

parent( a = 1 , toRemove = 2 )

编辑
对不起混乱。我修复了 child()。目的是让孩子列出...的内容

Edit2
这里更多的是一个真实世界的例子(但仍然相当简单,所以我们可以就它进行有用的对话)。通过递归调用父级。父级需要知道递归调用的深度。parent 之外的调用者不应该知道“深度”,也不应该在调用 parent() 时设置它。Parent 调用其他函数,在本例中为 child()。孩子需要价值......显然孩子不需要“深度”,因为父母生成它是为了自己使用。

parent = function( ... )
{

   depth = list(...)$depth      
   if ( is.null( depth ) )
   {
       depth = 1
   }  
   print( depth )

   # parent needs value of depth to perform various calculations (not shown here)

   if ( depth == 5 )
   {
       return()
   }
   else
   {
      # child doesn't need "depth" in ...
      child( ... ) 
   }

   # yikes!  now we've added a second, third, etc. depth value to ...
   parent( depth = depth + 1 , ... )

}


child = function(...) 
{       
    # does some magic    
}
4

5 回答 5

30

处理这些事情的一种方法是将child函数包装在 中parent,并使用一个定义,将您不想传递的任何参数放在参数child 之后...。例如:

parent <- function(...) {
    localChild <- function(..., toRemove) child(...)
    localChild(...)
}
child <- function(a) {
    a + 10
}

> parent(a = 1, toRemove = 10)
[1] 11

另一种方法是使用do.call()

parent2 <- function(...) {
    a <- list(...)
    a$toRemove <- NULL
    do.call(child2, a)
}
child2 <- function(b) {
    b + 10
}
> parent2(b = 1, toRemove = 10)
[1] 11

根据您的实际用例,这do.call()可能最接近您对问题的预期。

于 2011-08-11T15:30:03.233 回答
5

您的子功能是错误的。尝试

> child(a=1)
Error in str(a) : object 'a' not found

编辑:不再适用。

... 参数只能用于将参数传递给下一个函数。除非您将它们转换为列表,否则您无法轻松地从那里获取参数。所以你的子功能可能是:

child <- function(...)
{
  mc <- match.call()  # or mc <- list(...)
  str(mc$a)
}

这没有任何意义。您无法知道用户是否指定a。正确的方法是将a作为参数包含在您的函数中。是...将参数传递给下一个:

child <- function(a, ...){
    str(a,...)
}

然后你可以这样做:

parent <- function(...){

   mc <- match.call()
   mc$toRemove <- NULL
   mc[[1L]] <- as.name("child")
   eval(mc)

}

或使用建议的list(...)do.call()构造@Gavin。的好处match.call()是您也可以包含非点参数。这允许您的父函数为子函数指定默认值:

parent <- function(a=3, ...){
    ... (see above)
}
于 2011-08-11T15:40:29.190 回答
4

这是一个如何从...中取出项目并删除元素的示例,然后我使用 do.call 调用下一个函数:

parent <- function(...){
   funArgs <-  list(...)
   str(funArgs)
   ## remove the second item
   newArgs <- funArgs[-2]
   str(newArgs)
   ## if you want to call another function, use do.call
   do.call(child, newArgs)
  }

child = function(...)
{
  cat("Don't call me a child, buddy!\n")
  a <- list(...)
  str(a)
}


parent(a=1, b=2, c=3)

如果您需要向参数添加更多项目,而不是删除参数,请记住do.call喜欢命名列表,其中名称是参数名称,列表值是参数值。它在帮助文件中,但在最终弄清楚之前我有点挣扎。

于 2011-08-11T15:28:22.217 回答
3

你得到了一些很好的答案,但这里有一些简单的东西可以解决你的具体例子:

parent = function(...)
{

   a = list(...)
   str(a)
   a$toRemove = NULL  
   str(a)

   # attempt 1   
   child(a)   

   # attempt 2
   #child(...)
}

child = function(...)
{
    a <- as.list(...)   
    str(a)
}

parent( a = 1 , toRemove = 2 )

返回:

List of 2
 $ a       : num 1
 $ toRemove: num 2
List of 1
 $ a: num 1
List of 1
 $ a: num 1

您的原始版本引发错误,因为a未在child. 然后简单地使用as.list(...)in child(而不是 just list(...))似乎可以生成您想要的输出。请注意,我仅在此处使用您的尝试 1。

于 2011-08-11T15:37:09.753 回答
0

我不认为列出的答案可以解决问题,或者至少在我阅读时没有。假设您想将一些参数(例如 'xmax' 和 'xmin' )作为实际变量传递给 child(...)?
在孩子的环境中,它希望看到名为“xmax”和“xmin”的变量,而目前提供的示例似乎并未使这些变量可用。尝试插入一行

xmax-xmin -> xrange

进入 child() 函数,它会抛出一个错误。
我认为,原始问题的重点是允许将可选“...”变量的子集传递给 child() 。您可以为简单的情况定制解决方案,例如 sum(...),其中 sum(unlist(the_modified_list)) 有效。在更一般的情况下,我仍然看不到解决方案。我们可能需要将此问题提升到 R-help 邮件列表。

编辑:查看详细介绍 http://ucfagls.wordpress.com/2011/07/23/passing-non-graphical-parameters-to-graphical-functions-using/

于 2011-08-11T16:52:41.167 回答