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_组
参数的绘图函数,它们使用我无法影响的标准参数集调用。添加一个生成器确实有帮助,但这正是我在问题中所展示的。