为什么延迟评估在这个R函数中不起作用?

时间:2012-10-11 17:59:57

标签: r lazy-evaluation ellipsis

  

可能重复:
  How to write an R function that evaluates an expression within a data-frame

我想编写一个对data.frame进行排序的函数 - 而不是使用繁琐的order()。给出像

这样的东西
> x=data.frame(a=c(5,6,7),b=c(3,5,1))
> x
  a b
1 5 3
2 6 5
3 7 1

我想说的是:

sort.df(x,b)

所以这是我的功能:

sort.df <- function(df, ...) {
  with(df, df[order(...),])
}

我为此感到自豪。鉴于R的懒惰评估,我认为......参数只会在需要时进行评估 - 到那时它将在范围内,因为'with'。

如果我直接运行'with'行,它就可以了。但功能没有。

> with(x,x[order(b),])
  a b
3 7 1
1 5 3
2 6 5
> sort.df(x,b)
Error in order(...) : object 'b' not found

出了什么问题以及如何解决?例如,我经常在像plyr这样的软件包中看到这种“魔力”。有什么诀窍?

2 个答案:

答案 0 :(得分:9)

这将做你想要的:

sort.df <- function(df, ...) {
  dots <- as.list(substitute(list(...)))[-1]
  ord <- with(df, do.call(order, dots))
  df[ord,]
}

## Try it out
x <- data.frame(a=1:10, b=rep(1:2, length=10), c=rep(1:3, length=10))
sort.df(x, b, c)

这样:

sort.df2 <- function(df, ...) {
    cl <- substitute(list(...))
    cl[[1]] <- as.symbol("order")
    df[eval(cl, envir=df),]
}
 sort.df2(x, b, c)

答案 1 :(得分:7)

这是因为当你通过b时,你实际上并没有传递一个物体。在你的函数中添加一个browser,你会明白我的意思。我从某个互联网机器人那里偷了这个:

x=data.frame(a=c(5,6,7),b=c(3,5,1))

sort.df <- function(df, ..., drop = TRUE){
    ord <- eval(substitute(order(...)), envir = df, enclos = parent.frame())
    return(df[ord, , drop = drop])
}

sort.df(x, b)

会奏效。

如果您正在寻找一种在应用意义上做到这一点的好方法,那么

library(taRifx)
sort(x, f=~b)