定义匿名函数而不使用`function`关键字

时间:2018-09-25 07:07:20

标签: r

我可以定义和使用匿名函数并像这样调用它

x <- 1:3
sapply(x, function(x) x)

有时候,我觉得使用这样的函数太冗长了。还有另一种定义匿名函数的方法吗?

purrr包中,可以定义这样的匿名函数

map(x, ~.x)

但这仅在purrr上下文中有效。

5 个答案:

答案 0 :(得分:7)

您能做到多详细?您需要某种指示符,以表明这是一个函数,以某种方式表示自变量,以某种方式表示计算。使其“冗长”的唯一原因是“功能”有八个字母。如果您不希望这样做,请在应用中外部定义函数,然后获得sapply(x, foo),它简洁明了且易于理解,并且无需借助外部依赖项(purrrr)或非标准评估。

答案 1 :(得分:7)

1)gsubfn :: fn gsubfn package支持用于定义函数的公式表示法,与问题中提到的purrr不同,该方法仅适用于purrr函数,几乎可与任何函数兼容功能。

如果将匿名函数传递给另一个函数,则在示例中,匿名函数传递给sapply,然后在sapply前面加上fn$并使用args形式的公式表示法〜身体。如果缺少args,则假定主体中的自由变量是在主体中遇到的顺序的参数,因此在下面的第一个示例z中,将其视为单个参数。

library(gsubfn)

x <- 1:3
fn$sapply(x, ~ z)
## [1] 1 2 3

# same - specify arg
fn$sapply(x, z ~ z)
## [1] 1 2 3

# same - can use any variable name we like
fn$sapply(x, ~ x)
## [1] 1 2 3

# same
sapply(x, function(z) z)
## [1] 1 2 3

匿名函数可以具有任意数量的参数。以下是相同的:

fn$sapply(x, ~ u + 2 * v, v = 10)
## [1] 21 22 23

# same
fn$sapply(x, u + v ~ u + 2 * v, v = 10)
## [1] 21 22 23

# same
sapply(x, function(u, v) u + 2 * v, v = 10)
## [1] 21 22 23

2)magrittr

magrittr package支持用于定义单个参数函数的管道符号。参数必须为点。

library(magrittr)

x <- 1:3
sapply(x, . %>% {.})
## [1] 1 2 3

# same
sapply(x, function(x) x)
## [1] 1 2 3

# same
x %>% sapply(. %>% {.})
## [1] 1 2 3

3)lambda.r lambda.r package允许使用%as%定义以命名的函数。在这里,我们定义了一个名为fun的函数。

library(lambda.r)

x <- 1:3
fun(x) %as% x
sapply(x, fun)
## [1] 1 2 3

# same
fun <- function(x) x
sapply(x, fun)
## [1] 1 2 3

答案 2 :(得分:2)

'wrapr'软件包提供了几种缩写匿名函数的方法。在LINUX平台上(允许lambda字符成为可用于命名符号的“字母”取决于OS和语言环境),您可以执行以下操作:

library(wrapr)
λ <- lambda
sapply(1:10,λ(x,x^2))
#[1]   1   4   9  16  25  36  49  64  81 100

λ(x,y,x*y)(6,7)
#[1] 42

答案 3 :(得分:2)

  • L函数允许非常紧凑的函数定义,它从您提供给它的表达式中猜测函数的参数,对于简单的调用来说效果很好。
  • <!ELEMENT I ((P|L)+)> 使用pryr::f,它本身称为purrr,因此您也可以调用它们,尽管它并不那么冗长。
  • I wrote a package called lambda使公式符号与基数R(或具有较小设置的任何程序包)兼容,它正在进行中,但已经完全可用。仅用于交互式,请勿对其进行编程。

示例:

f

purrr::as_mapper

as_function

rlang::as_function

您可以将其分配给简短变量以使用紧凑语法:

aggregate(. ~ Species, iris, pryr::f(mean(range(.))))
#      Species Sepal.Length Sepal.Width Petal.Length Petal.Width
# 1     setosa         5.05        3.35         1.45        0.35
# 2 versicolor         5.95        2.70         4.05        1.40
# 3  virginica         6.40        3.00         5.70        1.95

as_mapper

aggregate(. ~ Species, iris, rlang::as_function(~mean(range(.))))
#      Species Sepal.Length Sepal.Width Petal.Length Petal.Width
# 1     setosa         5.05        3.35         1.45        0.35
# 2 versicolor         5.95        2.70         4.05        1.40
# 3  virginica         6.40        3.00         5.70        1.95

lambda

.. <- rlang::as_function
aggregate(. ~ Species, iris, ..(~mean(range(.))))

其他功能,例如aggregate(. ~ Species, iris, purrr::as_mapper(~mean(range(.)))) # Species Sepal.Length Sepal.Width Petal.Length Petal.Width # 1 setosa 5.05 3.35 1.45 0.35 # 2 versicolor 5.95 2.70 4.05 1.40 # 3 virginica 6.40 3.00 5.70 1.95 # devtools::install_github("moodymudskipper/lambda") library(lambda) attach_lambda() aggregate(. ~ Species, iris, ~mean(range(.))) # Species Sepal.Length Sepal.Width Petal.Length Petal.Width # 1 setosa 5.05 3.35 1.45 0.35 # 2 versicolor 5.95 2.70 4.05 1.40 # 3 virginica 6.40 3.00 5.70 1.95 base::Negatebase::vectorize ...有时可以帮助使代码更紧凑。

答案 4 :(得分:1)

我敢肯定,任何明智的R程序员在接下来的工作中都应认真对待,但似乎有点乐趣,这似乎行得通,并且消除了必须调用6个字母长的函数的麻烦

s=function(x,f)
{
    eval(parse(text = paste('y <- function(x)',deparse(substitute(f)),collapse='')))
    sapply(x,y)
}

所以现在使用s代替了sapply

s(1:3,x*2)
## [1] 2 4 6

x必须用作该函数的单个参数,这可能像地狱一样容易出错。