R 委派函数调用的便捷方法

R 委派函数调用的便捷方法,r,function,function-declaration,R,Function,Function Declaration,我有一系列类似的函数,它们都需要从数据帧中提取一些值。大概是这样的: foo_1 <- function(data, ...) { x <- data$x y <- data$y # some preparatory code common to all foo_X functions # .. do some boring stuff with x and y # pack and process the result into 'ret' re

我有一系列类似的函数,它们都需要从数据帧中提取一些值。大概是这样的:

foo_1 <- function(data, ...) {
  x <- data$x
  y <- data$y

  # some preparatory code common to all foo_X functions

  # .. do some boring stuff with x and y

  # pack and process the result into 'ret'
  return(ret)
}
foo_generator <- function(number) {

  tocall <- switch(1=foo_1, 2=foo_2, 3=foo_3) # etc.

  function(data, ...) {
    x <- data$x
    y <- data$y
    tocall(x, y, ...)
    # process and pack into ret
    return(ret)
}

foo_1 <- function(x, y, ...) {
  # do some boring stuff
}
然后我可以使用
foo_生成器(1)
而不是
foo_1
作为主函数的参数


有更好或更优雅的方式吗?我觉得我忽略了一些显而易见的东西。

在函数内部使用


foo_1另一种可能性是使用
list2env
将列表的组件保存到指定的环境中:

foo_1 <- function(data){
  list2env(data, envir = environment())
  x + y
}

foo_1(data.frame(x = 1:2, y = 3:4))

foo_1对我来说,要求仍然有点模糊,
但是,如果您的代码非常相似,您可以简单地将其围绕一个辅助函数,如示例中的
tocall
, 您的输入是一个类似列表的结构 (就像一个数据帧,它只是一列列表), 然后只需编写所有
foo.*
函数,以获取建议解决方案中的“拼接”参数, 然后使用
do.call

foo_1 <- function(x, y) {
  x + y
}

foo_2 <- function(x, y) {
  x - y
}

data <- list(x = 1:2, y = 3:4)

do.call(foo_1, data)
# [1] 4 6

do.call(foo_2, data)
# [1] -2 -2

foo_1我不确定以下内容是否是个好主意。这让我想起了一点宏编程。我想我不会这么做。您需要仔细地记录,因为它是意外的、令人困惑的、不自解释的

如果希望在不同的函数中重用相同的代码,可以选择将其创建为未计算的调用,并在不同的函数中计算该调用:

prepcode <- quote({
  x <- data$x
  y <- data$y
  }
)

foo_1 <- function(data, ...) {
  eval(prepcode)
  # some preparatory code common to all foo_X functions

  # .. do some boring stuff with x and y

  # pack and process the result into 'ret'
  return(list(x, y))
}

L <- list(x = 1, y = "a")
foo_1(L)
#[[1]]
#[1] 1
#
#[[2]]
#[1] "a"

prepcode我不确定我是否完全理解,但是你不能简单地将一个函数用于所有常见的东西,然后使用
list2env
将其解压缩到
foo\N
函数中吗?例如:

prepFun <- function(data, ...) {
    x <- data$x
    y <- data$y
    tocall(x, y, ...)
    # process and pack into a named list called ret
    # so you know specifically what the elements of ret are called
    return(ret)
}

foo_1 <- function(data, ...) {

  # Get prepFun to do the prepping, then use list2env to get the result in foo_1
  # You know which are the named elements, so there should be no confusion about
  # what does or does not get masked.
  prepResult <- prepFun(data, ...)
  list2env(prepResult)

  # .. do some boring stuff with x and y

  # pack and process the result into 'ret'
  return(ret)

}

prepFun你可能想得太多了。您说处理准备和打包的代码对于所有
foo\n
函数都是通用的。那么,我想,
#。。用x和y做一些无聊的事情
是每个函数的不同之处。如果是这种情况,那么只需创建一个以函数名为参数的
prep_和
函数,然后传入
foo_1
foo_2
,等等。例如:

prepFun <- function(data, ...) {
    x <- data$x
    y <- data$y
    tocall(x, y, ...)
    # process and pack into a named list called ret
    # so you know specifically what the elements of ret are called
    return(ret)
}

foo_1 <- function(data, ...) {

  # Get prepFun to do the prepping, then use list2env to get the result in foo_1
  # You know which are the named elements, so there should be no confusion about
  # what does or does not get masked.
  prepResult <- prepFun(data, ...)
  list2env(prepResult)

  # .. do some boring stuff with x and y

  # pack and process the result into 'ret'
  return(ret)

}

prep_和_pack我认为为这项任务定义函数工厂有点过火和混乱。您可以定义一个常规函数,并在将其传递给主函数时对其使用
purrr::partial()

比如:

foo <- function(data, ..., number, foo_funs) {
  tocall <- foo_funs[[number]])
  with(data[c("x", "y")], tocall(x, y, ...))
    # process and pack into ret
   return(ret)
}

foo_1 <- function(x, y, ...) {
  # do some boring stuff
}

foo_funs <- list(foo_1, foo_2, ...)

foo这与
attach
具有相同的缺点<代码>数据
可能包含大量其他内容,我无法控制它,也无法删除其他内容。考虑<代码>调整=9;使用(数据,打印(调整))
数据$adjustment!=NULL
。您定义了
foo_1
,因此您可以控制它所做的一切,以及它所需要的一切。这一一般性陈述当然是正确的,但将
结合使用有时是一种方法,可以通过使用基于数据的环境(我无法控制)来放松控制,您同意吗?当然,我可以将所有代码放在
with()
调用中,但是(I)它不是很优雅,(ii)它会增加可能出错的事情,我需要担心。或者我可以只使用我需要的东西来构造
data2
,然后在上面使用
。但是,我需要在每个函数中重复无聊的代码。更不用说我更喜欢调用
foo(x,y)
。解决方案是编写
foo\u 1
,这样就不必担心变量名冲突。但是,也有一些明确的要求,你没有在问题中提出。投票结束时不清楚……这是什么要求?另外,是的,当然解决方案是编写
foo_1
,这样我就不必担心变量名冲突,我只是说,将
一起使用是一种确保我确实需要担心变量名冲突的方法。这会有什么帮助?分配局部变量只是每个
foo_X
函数中需要完成的任务之一。您能否为变量分配和公共代码创建一个新函数,这样就不必重复多次?然后在foo_N函数中调用该函数?或者不把普通的东西放在一个函数中,把普通的代码部分放在你的全局环境中?我分配了赏金,因为你的答案得到了最多的选票;然而,没有一个解决方案适合我。例如,由于我将该函数作为参数传递给另一个函数,因此我无法控制如何调用该函数或为其提供额外的参数。我的解决方案是否仍然有效?您可以按自己喜欢的方式调用
foo\n
,但准备代码都很好地包含在
prepFun
中。还是我遗漏了什么?如果将
prep\u和\u pack
重写为函数生成器,会有帮助吗?例如,只需在1月份添加
generator就可以将内部函数的额外参数作为参数(或作为参数)传递到外部函数,例如
prep_和_pack(data=df,func=foo_1,func_args=list(arg1=val1,arg2=val2,…)
。我不太清楚你所说的“怎么叫它”是什么意思。你能更详细地描述你的问题吗?我正在为ggplot建立一个小部件工厂。这些函数是作为参数传递给
ggproto
draw_组
参数的绘图函数,它们使用我无法影响的标准参数集调用。添加一个生成器确实有帮助,但这正是我在问题中所展示的。