在R中将缺少的参数从函数传递到函数

Posted

技术标签:

【中文标题】在R中将缺少的参数从函数传递到函数【英文标题】:Passing missing argument from function to function in R 【发布时间】:2015-10-12 00:20:13 【问题描述】:

我了解到在函数中使用可选参数并使用 missing() 检查它们是一种常见的做法 (例如SO 22024082 中讨论的)

在本例中,round0 是可选参数(我知道,round0 可以定义为逻辑参数)。

foo = function(a, round0) 
    a = a * pi
    if(!missing(round0)) round(a)
    else a

但是如果我从另一个函数调用这个函数,我怎么能传递“缺失”呢?

bar = function(b) 
    if(b > 10) round1=T
    foo(b, round1)

如果 b

foo = function(a, round0) 
    a = a * pi
    print(missing(round0))
    print(round0)
    if(!missing(round0)) round(a)
    else a

并运行 bar(9) 输出为:

bar(9)
[1] FALSE
Error in print(round0) : object 'round1' not found
Called from: print(round0)

也就是说:round0没有丢失,但也无法访问?

我不想在 bar() 中使用不同的函数调用,如果 foo() 中有多个可选参数,我将不得不为每个丢失/未丢失的所有可选参数的组合编写一个函数调用。

是否可以通过“缺失”,或者其他解决方案适用于这个问题?

【问题讨论】:

通常,如果你以特定的形式调用一个函数,你应该确保你有所有的参数。在这里,我将在bar 的开头添加一个round1=F,并将foo 更新为if(!missing(round0) && round0)。缺少允许你调用foo(a)foo(a,T/F),如果你用两个参数调用它,第二个参数不会丢失并且必须是可解析的。 我的猜测是missing 在表示函数参数的承诺对象具有非空表达式槽时立即返回FALSE。在修改后的foo 函数中在a = a * pi 之后添加行print(substitute(round0)),然后执行foo(9)substitute 将提取表达式槽。它不会打印任何内容,即round0 的空表达式槽。现在试试bar(9)。这将打印round1。但是当您使用print 时,R 将尝试评估尚未定义的round1(惰性评估)。 【参考方案1】:

在您的示例中,round0 没有丢失,它设置为未定义的 round1(与丢失相反)。

一般而言,最好的方法是使用默认值,在您的情况下为FALSE

foo = function(a, round0 = FALSE) 
    a = a * pi
    if (!round0) round(a)
    else a


bar = function(b) 
    round1 <- FALSE
    if (b > 10) round1=TRUE
    foo(b, round1)

或者默认值在参数列表中不容易表达的地方:

foo = function(a, round0 = NULL) 
    a = a * pi
    if(!is.null(round0)) round(a)
    else a


bar = function(b) 
    round1 <- NULL
    if (b > 10) round1=TRUE
    foo(b, round1)

请注意,在这两种情况下,您都需要在调用函数中手动将参数设置为默认值。

如果需要,您还可以在 if 语句中调用带有或不带参数的 foo 函数:

bar = function(b) 
    if (b > 10) foo(b, TRUE) else foo(b)

@moody_mudskipper 的answer 展示了另一种显示如何生成缺失值的方法。

【讨论】:

最后的说法不准确。您可以通过将变量定义为quote(expr=)substitute()alist(x=1)[[1]] 来使变量丢失。前者效率最高。 rlang 有一个 missing_arg 函数,它也有同样的作用。请参阅下面我自己的答案。 @Moody_Mudskipper 谢谢,我不知道。我已经修改了我的答案以指向你的答案。【参考方案2】:

我最近遇到了类似的问题,想用一般的方式解决。我觉得可以按照下面函数g()的定义来做:

f <- function(a = 5, b = 3, c = 2, d = 7) 
  if (missing(a)) print("a is missing.")
  if (missing(b)) print("b is missing.")
  if (missing(c)) print("c is missing.")
  if (missing(d)) print("d is missing.")

  cat(a, b, c, d)


g <- function(a = 1, b = 1, c = 1, d = 1) 
  args <- as.list(match.call())
  args[[1]] <- NULL # remove first list element, it's the function call
  do.call(f, args, envir = parent.frame())

以下是我们在使用不同的参数集调用 g() 时得到的结果:

> g()
[1] "a is missing."
[1] "b is missing."
[1] "c is missing."
[1] "d is missing."
5 3 2 7

> g(a = 3)
[1] "b is missing."
[1] "c is missing."
[1] "d is missing."
3 3 2 7

> g(b = 10, c = 10)
[1] "a is missing."
[1] "d is missing."
5 10 10 7

如果您不想将所有参数交给下一个函数或想添加一些参数,您可以添加到args 列表或从列表中删除。例如,请参阅以下函数 g(),它以一般方式执行此操作:

g <- function(a = 1, b = 1, c = 1, x = 1, y = 1, z = 1) 
  f_args <- c("a", "b", "c") # arguments we want to hand off to function f

  # obtain the list of arguments provided
  args <- as.list(match.call())
  # remove first list element, it's the function call
  args[[1]] <- NULL
  # remove the arguments that are not listed in f_args
  args <- args[na.omit(match(f_args, names(args)))]

  # now add argument d, we always want it to be 0:
  args <- c(args, list(d = 0))
  do.call(f, args, envir = parent.frame())

以下是我们在使用不同的参数集调用 g() 时得到的结果:

> g()
[1] "a is missing."
[1] "b is missing."
[1] "c is missing."
5 3 2 0

> g(a = 3)
[1] "b is missing."
[1] "c is missing."
3 3 2 0

> g(b = 10, c = 10)
[1] "a is missing."
5 10 10 0

有关do.call() 的更多信息,请参阅this answer。

【讨论】:

【参考方案3】:

您可以使用 substitute() 不带参数来创建缺失对象。

在您的情况下,我们可以在 else 子句中将 round1 设为缺失对象:

foo = function(a, round0) 
  a = a * pi
  if(!missing(round0)) round(a)
  else a


bar = function(b) 
  if(b > 10) round1=T else round1 <- substitute()
  foo(b, round1)


bar(9)
#> [1] 28.27433

由reprex package (v0.3.0) 于 2019 年 10 月 24 日创建

【讨论】:

missing() 需要它的输入是某种东西(它的名字在这方面是矛盾的)。这个东西是一个空表达式,看起来substitute()可以创建一些,你也可以做alist(x=)[[1]]。对于冗长的答案,我们需要进入 C 实现,我对此了解不多。【参考方案4】:

rlang 还提供了一个函数missing_arg(),它可以使参数丢失。

foo = function(a, round0) 
  a = a * pi
  if(!missing(round0)) round(a)
  else a


bar = function(b) 
  if(b > 10) round1 <- TRUE else round1 <- rlang::missing_arg()
  foo(b, round1)


foo(9)
#> [1] 28.27433
bar(9)
#> [1] 28.27433

由reprex package 创建于 2020-12-02 (v0.3.0)

【讨论】:

以上是关于在R中将缺少的参数从函数传递到函数的主要内容,如果未能解决你的问题,请参考以下文章

在 C++ 中将不同大小的常量数组作为函数参数传递

将变量名称作为参数从外部函数传递到 R 中的内部函数时出现问题?

如何在bash脚本中通过函数调用将参数/参数从一个函数传递到另一个函数[重复]

是否可以在 Flutter 的函数中将类作为参数传递?

如何在一个条目中将RGB作为单独的参数传递给函数

如何在用户定义的函数中将数据库列作为参数传递?