Why is there no lazy rating in this function R?

Possible duplicate:
How to write a function R that evaluates an expression in a data frame

I want to write a function that sorts data.frame - instead of using bulky order (). Given something like

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

I want to say something like:

 sort.df(x,b) 

So here is my function:

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

I was really proud of it. Given R's lazy rating, I realized that the parameter ... would only be evaluated when necessary, and by then it would be in scope because of the "c".

If I run the string β€œc” directly, it works. But the function does not work.

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

What is wrong and how to fix it? For example, I often see such β€œmagic” in packages like plyr. What a trick?

+8
r ellipsis lazy-evaluation
source share
2 answers

This is because when you pass b, you are not actually passing the object. Put a browser inside your function and you will understand what I mean. I stole it from some internet robot somewhere:

 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) 

will work.

This will happen if you are looking for a good way to do this in an applied sense:

 library(taRifx) sort(x, f=~b) 
+7
source share

This will do what you want:

 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) 

And so it will be:

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

All Articles