我有一系列类似的功能,所有这些功能都需要从数据帧中提取一些值。像这样:
function [] = q56982381()
hF = uifigure(); hAx = uiaxes(hF);
hAx.XScale = 'log';
hP = plot( hAx, 1 : 10 );
% Invoke the datacursor manager:
dcm_obj = datacursormode(hF);
hTip = dcm_obj.createDatatip(hP); % Don't specify any further inputs at this stage
% Wait until the figure loaded:
drawnow; pause(0.1); % or mlapptools.waitForFigureReady(hF); (see note at the bottom)
% Modify the datatip position:
hTip.Position = [2, 2, 0];
然后将这些函数作为其他函数的参数提供(让我们将其称为“主函数”。我无法修改主函数)。
我不想使用foo_1 <- function(data, ...) {
x <- data$x
y <- data$y
# .. do some boring stuff with x and y
# pack and process the result into 'ret'
return(ret)
}
而不是将其分配给data$x
并使用x
,因为它使无聊的东西难以阅读。但是,我现在需要在所有x
,x <- data$x
...函数中编写foo_1
(等等)。这很烦人并且使代码混乱。此外,打包和处理对于所有foo_2
函数都是通用的。
什么是优雅而简洁的方式?
一种可能性是foo_N
数据框(或使用attach()
,如Hong在下面的答案中所建议的那样),但是我不知道我的名字空间中还有其他变量:附加数据可以掩盖我在with()
中使用的其他变量。另外,最好使用显式参数调用fun_1
函数,这样可以更轻松地查看它们的需求和作用。
我想到的下一个可能性是这样的构造:
foo_N
然后我可以使用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_generator(1)
作为主函数的参数。
有更好或更优雅的方式吗?我觉得我正在忽略这里很明显的东西。
答案 0 :(得分:4)
您可能想得太多。您说关于准备和打包的代码是所有foo_n
函数所共有的。那么,我假设# .. do some boring stuff with x and y
是每个函数都不同的地方。如果是这种情况,则只需创建一个以函数名称作为参数的prep_and_pack
函数,然后传入foo_1
,foo_2
等。例如:
prep_and_pack <- function(data, func){
x <- data$x
y <- data$y
# preparatory code here
xy_output <- func(x, y) # do stuff with x and y
# code to pack and process into "ret"
return(ret)
}
现在,您可以创建自己的foo_n
函数,用x
和y
做不同的事情:
foo_1 <- function(x, y) {
# .. do some boring stuff with x and y
}
foo_2 <- function(x, y) {
# .. do some boring stuff with x and y
}
foo_3 <- function(x, y) {
# .. do some boring stuff with x and y
}
最后,您可以将对prep_and_pack
的多个调用传递到主函数中,其中foo_1
等通过func
参数传递:
master_func(prep_and_pack(data = df, func = foo_1),
prep_and_pack(data = df, func = foo_2),
prep_and_pack(data = df, func = foo_3)
)
您也可以在switch
中使用prep_and_pack
和/或完全放弃foo_n
函数,而转而使用if-else条件来处理各种情况,但我认为以上内容一直存在一切都很干净。
答案 1 :(得分:2)
我不确定以下是一个好主意。它使我想起了一些使用宏进行编程的过程。我不认为我会这样做。您需要仔细记录文档,因为它出乎意料,令人困惑且不言自明。
如果要在不同的函数中重用相同的代码,可以选择将其创建为未评估的调用,然后在不同的函数中评估该调用:
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
作为foo_1
的参数,以确保不存在任何范围界定问题。
答案 2 :(得分: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
答案 3 :(得分:1)
我不确定我是否完全理解,但是您不能简单地对所有常见的东西使用一个函数,然后使用foo_N
将其解压缩到list2env
函数中吗?例如:
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)
}
希望这就是您想要的!
答案 4 :(得分:1)
我认为为此任务定义一个函数工厂有点矫kill过正和令人困惑。您可以定义一个通用函数,并将其传递给主函数时在其上使用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, ...)
然后致电master_fun(fun = purrr::partial(foo, number =1) , ...)
答案 5 :(得分:0)
在函数内使用with
:
foo_1 <- function(data, ...) {
with(data, {
# .. in here, x and y refer to data$x and data$y
}
}
答案 6 :(得分:0)
另一种可能性是使用list2env
将列表的组件保存到指定的环境中:
foo_1 <- function(data){
list2env(data, envir = environment())
x + y
}
foo_1(data.frame(x = 1:2, y = 3:4))
另请参阅this question。