Reputation: 3932
I'm struggling to understand why does this doesn't work.
df <- data.frame(a=1:10, b=1:10)
foo <- function(obj, col) {
with(obj, ls())
with(obj, print(col))
}
foo(df, a)
[1] "a" "b"
Error in print(col) : object 'a' not found
If this does work:
with(df, print(a))
Upvotes: 8
Views: 11797
Reputation: 226182
with
is handy and improves readability in an interactive context but can hurt your brain in a programming context where you are passing things back and forth to functions and dealing with things in different environments. In general within R, using symbols rather than names is a sort of "semantic sugar" that is convenient and readable in interactive use but mildly deprecated for programming [e.g. $
, subset
]). If you're willing to compromise as far as using a name ("a"
) rather than a symbol (a
) then I would suggest falling back to the simpler obj[[col]]
rather than using with
here ...
So, as a self-contained answer:
foo <- function(object,col) {
print(names(object))
print(object[[col]])
}
If you wanted to allow for multiple columns (i.e. a character vector)
foo <- function(object,col) {
print(names(object))
print(object[col])
}
edit: refraining from using subset
with a function, at @hadley's suggestion
(this will print the answer as a data frame, even if a single column is selected, which may not be what you want).
Upvotes: 13
Reputation: 7561
In function argument col is evaluated before using in function with (that opposite to interactive use). Here you have two solutions to this problem.
foo1 <- function(obj, col) {
with(obj, print(eval(col)))
}
foo1(mydf, quote(a))# here you have to remember to quote argument
foo2 <- function(obj, col) {
col <- as.expression(as.name(substitute(col)))#corrected after DWIN comment
with(obj, print(eval(col)))
}
foo2(mydf, a)# this function does all necessary stuff
Upvotes: 1
Reputation: 44648
Anything that is passed to a function must be an object, a string or a number. There are two problems with this:
What you want is more like:
foo <- function(obj, col) {
print(with(obj, ls()))
with(obj, print(obj[[col]]))
}
foo(df, "a")
Or if you're only looking for the one column to be printed:
foo <- function(obj, col) {
with(obj, print(obj[[col]]))
}
foo(df, "a")
Upvotes: 4