从循环变量中获取函数名称

时间:2015-03-29 18:24:37

标签: r

我需要遍历许多函数,并在函数名称旁边绘制/打印结果。我了解到(this question/answer)我必须使用substitute / eval。如果每个函数名本身都包含在substitute()中,则可以很好地工作(参见下面的(A)和(B))。有没有办法自动化这个,例如使用类似sapply的结构? (C)明显失败,因为substitute也包含了c()条款,但也许有一些我错过了(D)的工作?还是其他任何想法?或者没有办法?

这就是我的尝试(小例子,真实代码有更多功能和绘图的东西)。

# A
x <- c(1:10)
my.fun <- substitute(mean)                                 # works
print(paste(deparse(my.fun), ": ", eval(my.fun)(x), sep=""))

# B
for (my.fun in c(substitute(mean), substitute(median))) {  # works, but lots of typing for longer function lists
  print(paste(deparse(my.fun), ": ", eval(my.fun)(x), sep=""))
}

# C
for (my.fun in substitute(c(mean, median))) {              # error: invalid for() loop sequence
  print(paste(deparse(my.fun), ": ", eval(my.fun)(x), sep=""))
}

# D
for (my.fun in sapply(c(mean, median), substitute)) {      # error: '...' used in an incorrect context
  print(paste(deparse(my.fun), ": ", eval(my.fun)(x), sep=""))
}

# E                                                        # also not helpful
my.functions <- c(mean, median)
my.fun.2 <- NULL
for (i in 1:2) {
  my.fun.2 <- c(my.fun.2, substitute(my.functions[i]))
}
# my.fun.2
# [[1]]
# my.functions[i]
# [[2]]
# my.functions[i]

1 个答案:

答案 0 :(得分:1)

这个“单线”怎么样? :)

> x <- c(1:10)
> f <- function(...)
+     sapply(
+         sapply(
+             as.list(substitute(list(...)))[-1L],
+             deparse),
+         function(fn)
+             get(fn)(x))
> f(mean, median)
  mean median 
   5.5    5.5 

简而言之,您可以将函数作为多个参数传递,然后在逐个实际评估函数之前快速deparse。所以上面的函数有一些额外的评论:

#' Evaluate multiple functions on some values
#' @param ... any number of function that will take \code{x} as the argument
#' @param x values to be passed to the functions
#' @examples
#' f(mean, median)
#' f(mean, median, sum, x = mtcars$hp)
f <- function(..., x = c(1:10)) {

    ## get provided function names
    fns <- sapply(as.list(substitute(list(...)))[-1L], deparse)

    ## run each function as an anonymous function on "x"
    sapply(fns, function(fn) get(fn)(x))

}

或者使用do.call而不是后一个匿名函数:

f <- function(..., x = c(1:10)) {

    ## get provided function names
    fns <- sapply(as.list(substitute(list(...)))[-1L], deparse)

    ## run each function on "x"
    sapply(fns, do.call, args = list(x))

}