将列表的元素提取为 r 中自定义函数中的单个参数

Extract the elements of list as individual arguments within custom function in r

我在尝试将参数列表传递给自定义函数时遇到问题,但我希望函数的第一部分检查某些参数是否为 NULL,然后将值赋值为零,如果那是真实的。我发现了一个类似的问题 ,但它并没有帮助我找出我的特定问题。我试图将 4 个参数(aa、bb、dd 和 ff)传递给函数,然后检查 cc 和 ee 是否为 NULL。如果是这样,那么我想在函数的第一部分将 NULL 值(在本例中为 cc 和 ee)定义为零。我认为问题在于解包或取消列出 x 以便函数识别正在传递的参数。

考虑以下代码:

test <- list(aa = 2, bb = 0.5, dd = 2, ff = 16)

testfunc <- function(x, aa=NULL, bb=NULL, cc=NULL, dd=NULL, ee=NULL, ff=NULL) {
          
  unlist(x, recursive = TRUE, use.names = TRUE)
  
  if(!is.null(aa)) aa <- 0
  if(!is.null(bb)) bb <- 0
  if(!is.null(cc)) cc <- 0
  if(!is.null(dd)) dd <- 0
  if(!is.null(ee)) ee <- 0
  if(!is.null(ff)) ff <- 0

  q <- list(aa, bb, cc, dd, ee, ff)
  
  return(q)
}

testfunc(test)

此代码有效,但它 returns 所有 NULL 值。如果我在定义函数时删除所有 NULL 调用,则会出现以下错误,“testfunc(test) 错误:未找到对象 'aa'”

testfunc <- function(x) {
          
  unlist(x, recursive = TRUE, use.names = TRUE)
  
  if(!is.null(aa)) aa <- 0
  if(!is.null(bb)) bb <- 0
  if(!is.null(cc)) cc <- 0
  if(!is.null(dd)) dd <- 0
  if(!is.null(ee)) ee <- 0
  if(!is.null(ff)) ff <- 0

  q <- list(aa, bb, cc, dd, ee, ff)
  
  return(q)
}

testfunc(test)

也许将测试定义为数据框而不是列表会有所帮助?感谢您的帮助!

像这样的事情怎么样:

test <- list(aa = 2, bb = 0.5, dd = 2, ff = 16)

testfunc <- function(x, aa=NULL, bb=NULL, cc=NULL, dd=NULL, ee=NULL, ff=NULL) {
          
  unlist(x, recursive = TRUE, use.names = TRUE)
  
  if(!is.null(aa)) aa <- 0
  if(!is.null(bb)) bb <- 0
  if(!is.null(cc)) cc <- 0
  if(!is.null(dd)) dd <- 0
  if(!is.null(ee)) ee <- 0
  if(!is.null(ff)) ff <- 0

  q <- list(aa, bb, cc, dd, ee, ff)
  
  return(q)
}

testfunc(test)
# $aa
# [1] 2
# 
# $bb
# [1] 0.5
# 
# $cc
# [1] 0
# 
# $dd
# [1] 2
# 
# $ee
# [1] 0
# 
# $ff
# [1] 16

这是您要找的吗?关键是包装 formals() in list(),从而获得 testfunc().

的所有(“正式”)参数的命名列表

我对你的问题的解释是,你想将命名列表作为 x 参数传递给 testfunc(),其中包含命名值以覆盖传递给 testfunc() 的其他参数x。此列表可能是“不完整的”,因为它不一定命名所有其他参数(如 ccee)。那些没有被覆盖的保持原样;除非它们拥有默认值 NULL,在这种情况下它们将转换为 0.

使用上面的formals(),我们可以定义一个testfunc()

testfunc <- function(x, aa = NULL, bb = NULL, cc = NULL, dd = NULL, ee = NULL, ff = NULL) {
  # Capture what values were passed to what parameters of 'testfunc()'.
  params <- as.list(formals())
  param_names <- names(params)
  
  # For convenience, record the named variables listed under 'x'.
  x_names <- names(x)
  
  
  # Process each parameter (besides 'x' itself).
  for(p_name in param_names[param_names != "x"]) {
    # If the parameter is named in 'x', override it with the value from 'x'.
    if(p_name %in% x_names) {
      assign(p_name, x[[p_name]])
    }
    # Otherwise, leave the parameter alone...unless it is NULL and should be
    # replaced with 0.
    else if(is.null(get(p_name))) {
      assign(p_name, 0)
    }
  }
  
  
  # ...
  # Any further operations; where parameters can be referenced like any other parameter
  # in any other function, rather than having to be 'unlist'ed from 'x'.
  # ...
  
  
  # Explicitly name the parameters in the output list.
  q <- list(
    aa = aa,
    bb = bb,
    cc = cc,
    dd = dd,
    ee = ee,
    ff = ff
  )
  
  return(q)
}

这样调用

test <- list(aa = 2, bb = 0.5, dd = 2, ff = 16)

testfunc(test)

产生以下 list 作为输出:

$aa
[1] 2

$bb
[1] 0.5

$cc
[1] 0

$dd
[1] 2

$ee
[1] 0

$ff
[1] 16

备注

我优先考虑x。也就是说,我假设您想要在 x 中保留 明确指定 的任何 NULL。所以明确地给 x 一个 NULL 元素,比如 aa 这里

test <- list(aa = NULL, bb = 0.5, dd = 2, ff = 16)
testfunc(test)

将在输出中为 aa 生成 NULL

$aa
NULL

$bb
[1] 0.5

$cc
[1] 0

$dd
[1] 2

$ee
[1] 0

$ff
[1] 16

如果您想覆盖此行为,并确保 any NULL 在输出中被 0 替换,则只需更改 else if 到一个 if,在函数定义的第 18 行:

    # ...
    if(is.null(get(p_name))) {
      assign(p_name, 0)
    }
    # ...

提示

您的原始解决方案失败,因为您使用了 !is.null() 而不是 is.null();所以你避免0覆盖任何NULL

如果您希望 unlist(x) 使用 x 的内容填充 testfunc() 的环境,那您就大错特错了。 unlist() 所做的只是将 x“扁平化”成其原子组件的(均质化)向量;所以我们得到

x <- list(
  a = 1,
  list(
    b = TRUE,
    "hi"
  )
)

unlist(x, recursive = TRUE, use.names = TRUE)

#>     a      b        
#>   "1" "TRUE"   "hi" 

均质化为(已命名)character 向量。您的代码惰性地 returns 这个值并继续前进。

只有使用 assign("a", 1)(等等)之类的东西,您才能达到将这些值作为命名变量实际填充到您的环境中的效果。