【问题标题】:Can I remove an element in ... (dot-dot-dot) and pass it on?我可以删除 ... (dot-dot-dot) 中的元素并将其传递吗?
【发布时间】:2011-10-25 02:19:31
【问题描述】:

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

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()。目的是让孩子列出...的内容。

编辑2
这里更多的是一个真实世界的例子(但仍然相当简单,所以我们可以就它进行有用的对话)。通过递归调用父级。父母需要知道递归调用的深度。 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    
}

【问题讨论】:

    标签: r ellipsis


    【解决方案1】:

    这是一个如何从...中取出项目并删除元素的示例,然后我使用 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 喜欢命名列表,其中名称是参数名称,列表值是参数值。它在帮助文件中,但在最终弄清楚之前我有点挣扎。

    【讨论】:

    • 我认为没有那么复杂。试试funArgs &lt;- list(...)
    • 答案中应该是注释的示例不是 list(...) 的失败,它使用列表作为参数调用 mean()。我不知道list(...) 不起作用的情况。
    【解决方案2】:

    处理这些事情的一种方法是将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() 可能最接近您对问题的预期。

    【讨论】:

    • Gavin - 如果父级在“...”之前有一些命名参数,我将如何在 do.call 中传递这些参数?大概我必须将它们添加到“a”中?
    • Gavin - 对不起...我的意思是问是否有一些编程方式可以将其他命名参数添加到“a”。显然我可以手动添加它们,但如果我在路上添加更多参数,我必须记住更新“a”
    • @SFun28 是的;假设parent() 有参数xy...child(x, y, a),但没有b。如上图所示去掉b (dots &lt;- list(...); dots$b &lt;- NULL),然后以do.call(child, c(dots, x = x, y = y) 为例。就像我说的,我展示哪个成语将取决于你真正想要做什么。 localFoo() 技巧在基础 R 中的绘图代码中被大量使用,以将图形参数和相关参数传递给其他绘图代码。我有一个blog post
    • 我们的评论在以太中交叉。一种方法可能是使用match.call() 成语。例如。 foo &lt;- function(a, b, c, ...) as.list(match.call())[-1] 返回一个列表,试试看:foo(a = 1, b = 2, c = 3, d = 4) 然后你从该列表中删除你不想要的变量并将其传递给 do.call。有很多方法可以给这只猫剥皮——这在很大程度上取决于上下文。无论如何,作为编码员,您可以同时访问parent()child(),如果您更新一个,就可以更新另一个。更简单的代码更容易阅读/理解
    • @SFun28 :然后看我的回答。并且在使用 match.call 时,请注意 eval() 起作用的帧。 lm() 函数使用这种结构,但它会给出相当奇怪的结果。
    【解决方案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 中定义,因此您的原始版本引发了错误。然后在child 中简单地使用as.list(...)(而不是仅仅list(...))似乎会生成你想要的输出。请注意,我仅在此处使用您的尝试 1。

    【讨论】:

    • joran - 孩子不应该知道“a”。 child 的目的只是列出“...”以测试 toRemove 是否已从作为父输入的 ... 中删除
    • 对不起...意识到我的子函数有错误。固定的。我的意图不是在子函数中有一个,而是列出...的内容
    • @SFun28 抱歉,我一定误解了您要找的内容。
    • @SFun28 我们的信息相互交叉...这更有意义!我怀疑我的答案是你要找的,但考虑到你的编辑,它似乎至少在主题上足够我不会删除它......
    • 是的……让我们把这个答案留在这里,对其他搜索该主题的人很有用
    【解决方案4】:

    你的子函数是错误的。试试

    > 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)
    
    }
    

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

    parent <- function(a=3, ...){
        ... (see above)
    }
    

    【讨论】:

    • Joris - 固定子函数。我的意思是将 ... 转换为 list 和 str
    • @SFun28:我明白了。好吧,这让我的例子有点奇怪,但我仍然按照 Gavin 的要求将它留在这里,以说明 match.call() 的使用
    • Joris - 是的,请留在这里。这对社区来说是非常好的信息。
    【解决方案5】:

    我不认为列出的答案可以解决问题,或者至少在我阅读时没有。假设您想将一些参数(例如 '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/

    【讨论】:

    • Carl - 我们无法访问 xmin 和 xmax 的原因是它们没有在参数列表中明确指定。 ... 的目的是说“还有一些我不需要的其他参数,但我正在调用可能需要它们的函数”。如果 child 需要 xmax,它将显式列出 xmax 作为参数。当然,孩子可以通过将...转换为列表来访问...内的xmax
    • Carl - 感谢您提供指向我的博客文章的链接。这描述了我在回答中提到的localFoo() 成语。这个特定问答的一个问题是,不清楚 OP 的问题是具体的还是笼统的。我从一般的角度写了我的答案。我还是不太明白@SFun28 真正想要做什么——需要再次阅读cmets。
    • SFun28: child 可能不需要need xmax,但它甚至无法访问 xmax,直到该变量被正确传递给它。我的观点是,您不能将现有的 R 函数用作“子”函数,因为该函数不会设置为取消列出接收到的变量。
    • 以上链接指向“私人”wordpress 博客。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-01-20
    • 2020-03-26
    • 1970-01-01
    • 1970-01-01
    • 2016-03-18
    • 2021-11-06
    相关资源
    最近更新 更多