9.5 多个输入的应用函数
lapply
的缺点之一是它的函数参数只能循环作用于单个向量参数。另一个缺点是:对于作用于每个元素的函数,你不能访问该元素的名称。
mapply
是“多参数列表应用(multiple argument list apply)”的简称,它能让你传入尽可能多的向量作为参数,这解决了上面的第一个问题。常见的用法是传入一个列表,再传入另一个列表作为前者的名字,这就解决了第二个问题。有点烦人的是,为了容纳任意数目的向量参数,参数的顺序被改变了。对于mapply
,每一个传递的参数都是函数:
msg <- function(name, factors)
{
ifelse(
length(factors) == 1,
paste(name, "is prime"),
paste(name, "has factors", toString(factors))
)
}
mapply(msg, names(prime_factors), prime_factors)
## two three
## "two is prime" "three is prime"
## four five
## "four has factors 2, 2" "five is prime"
## six seven
## "six has factors 2, 3" "seven is prime"
## eight nine
## "eight has factors 2, 2, 2" "nine has factors 3, 3"
## ten
## "ten has factors 2, 5"
在默认情况下,mapply
与sapply
的表现相同,且会尽量地简化输出。通过传递参数SIMPLIFY = FALSE
可以关闭此行为(使它表现得更像lapply
)。
即时向量化(Instant Vectorization)
Vectorize
是mapply
的包装函数。通常它接受一个标量作为输入参数,并返回一个新的接受向量的函数。下一个函数不是向量化的,因为它使用了switch
,而这需要它的输入参数为标量:
baby_gender_report <- function(gender)
{
switch(
gender,
male = "It's a boy!",
female = "It's a girl!",
"Um..."
)
}
如果把向量传入到函数中,则会抛出一个错误:
genders <- c("male", "female", "other")
baby_gender_report(genders)
从理论上说,完全可以重写一个函数,使它变成向量化的。但更简单的方法是使用Vectorize
函数:
vectorized_baby_gender_report <- Vectorize(baby_gender_report)
vectorized_baby_gender_report(genders)
## male female other
## "It's a boy!" "It's a girl!" "Um..."