“万人往LVR”同学的函数在引用"character"的实参时,是没有问题的。比如:
- # 函数定义
- fun <- function(df, i) {
- table(df[, i])
- }
- # 函数效果检验
- > fun(airquality, "Month")
- 5 6 7 8 9
- 31 30 31 31 30
- > fun(airquality, 5L)
- 5 6 7 8 9
- 31 30 31 31 30
- > fun(airquality, 5.9)
- 5 6 7 8 9
- 31 30 31 31 30
复制代码可以看到,当‘i’的实参value为"character"、"integer"、"numeric"等类型的值时,都是可以正常引用的。不过注意,当是"numeric"时,实际引用的列数是‘i’的value被truncated后的值,并非四舍五入后的值。
“jiangbeilu”同学用到了substitute()和deparse()函数,是涉及了R语言很牛逼的一个特性,即:R has powerful tools for computing not only on values, but also on the actions that lead to those values.——by Hadley Wickham。上面这个特点能够在我们这个实际案例中发挥什么作用呢?至少其中一条,可以让‘i’的实参不加引号,就可以正常使用,也就是说,fun(airquality, Month)和fun(airquality, "Month")都能正常运行,就像library(ggplot2)和library("ggplot2")都正确一样。
- # 函数定义
- fun2 <- function(df, i) {
- i <- as.character(substitute(i))
- return(table(df[, i]))
- }
- # 函数效果检验
- > identical(fun2(airquality, "Month"), fun2(airquality, Month))
- [1] TRUE
复制代码当然,这个函数没有什么用,纯粹是为了举个例子,因为,它不能处理 i 为5、5.5、5L时的情况,而且如果 i 的值是个向量,也无法正确引用,要完善这个函数稍微复杂一点,我就引用Hadley Wickham的示范代码如下:
- # 函数定义
- fun3 <- function(df, i) {
- i <- substitute(i)
- i_pos <- setNames(as.list(seq_along(df)), names(df))
- pos <- eval(i, i_pos)
- table(df[, pos, drop = FALSE])
- }
- # 函数效果检验
- > fun3(airquality, Month)
- 5 6 7 8 9
- 31 30 31 31 30
- > fun3(airquality, "Month")
- 5 6 7 8 9
- 31 30 31 31 30
- > fun3(airquality, 5L)
- 5 6 7 8 9
- 31 30 31 31 30
- > fun3(airquality, 4:5)
- Month
- Temp 5 6 7 8 9
- 56 1 0 0 0 0
- 57 3 0 0 0 0
- 58 2 0 0 0 0
- 59 2 0 0 0 0
- # ......
- # 结果省略大部分
复制代码就实用性而言,“万人往LVR”同学的函数就简洁够用了。