Is there a way to pass object name into do.call() function?
For example:
#First make a function that will return the name of object itself.
PrintObjectName <- function(obj){
print(deparse(substitute(obj)))
}
data(iris)
PrintObjectName(iris)
[1] "iris" #This is what I want
do.call(what="PrintObjectName", args=list(obj=iris))
#The output is a messy stuff
You want to use alist within your call to do.call.
alist handles its arguments as if they described function arguments. So the values are not evaluated
do.call(what="PrintObjectName", args=alist(obj=iris))
# [1] "iris"
or you could use quote
do.call(what="PrintObjectName", args=list(obj=quote(iris)))
Related
The title is a bit loose. I would like to create a function that takes a list name as a variable, and assigns elements to that list. So far, I can access the list's elements via its name in the my_fun function. I can then modify the list within the function (using the function parameter), and print to verify that the assignment has worked. Of course, I'm not saving any of this to the global environment, so when I call the list outside of the function, it hasn't changed.
my_list <- list('original_element')
my_fun <- function(some_list) {
# check that I can access the list using the parameter name
print(some_list[[1]])
# modify the list
some_list[[1]] <- 'element_assigned_in_function'
# check that the list was modified
print(some_list[[1]])
}
my_fun(my_list)
# [1] "original_element"
# [1] "element_assigned_in_function"
# of course, my_list hasn't been modified in the global environment
my_list
# [[1]]
# [1] "original_element"
My question is, how could you assign new elements to this list within the function and store them in the global environment? If I simply try to make the assignment global with <<-, the following error is thrown:
Error in some_list[[1]] <<- "element_assigned_in_function" :
object 'some_list' not found
I've tried to use assign and set envir = .GlobalEnv, but that doesn't work and I don't think assign can be used with list elements. I suspect that there may be some quoting/unquoting/use of expressions to get this to work, but I haven't been able to figure it out. Thank you.
First of all, I'll be clear that I do not encourage assigning values to variables from inside the function in global environment. Ideally, you should always return the value from the function which you want to change. However, just for demonstration purpose here is a way in which you can change the contents of the list from inside the function
my_fun <- function(some_list) {
list_name <- deparse(substitute(some_list))
some_list[[1]] <- 'element_assigned_in_function'
assign(list_name, some_list, .GlobalEnv)
}
my_list <- list('original_element')
my_fun(my_list)
my_list
#[[1]]
#[1] "element_assigned_in_function"
I have a problem with elipsis usecase. My function accepts list of objects, let's call them objects of class "X". Now, objects X are being processed inside of my function to class "Xs", so I have list of "Xs" objects. Function that I import from other package can compute multiple "Xs" objects at once but they have to be enumerated (elipsis mechanic), not passed as list. Is there a way how to solve it? I want something like this
examplefun <- function(charlist){
nums <- lapply(charlist, as.numeric)
sum(... = nums)
}
Of course example above throws an error but it shows what i want to achieve. I tried to unlist with recursive = FALSE ("X" and "Xs" are the list itself) but it does not work.
If there is no solution then:
Let's assume I decideed to accept ... insted of list of "X" objects. Can I modify elipsis elements (change them to "Xs") and then pass to function that accepts elipsis? So it will look like this:
examplefun2 <- function(...){
function that modify object in ... to "Xs" objects
sum(...)
}
In your first function, just call sum directly because sum works correctly on vectors of numbers instead of individual numbers.
examplefun <- function (charlist) {
nums <- vapply(charlist, as.numeric, numeric(1L))
sum(nums)
}
(Note the use of vapply instead of lapply: sum expects an atomic vector, we can’t pass a list.)
In your second function, you can capture ... and work with the captured variable:
examplefun2 <- function (...) {
nums <- as.numeric(c(...))
sums(nums)
}
For more complex arguments, Roland’s comment is a good alternative: Modify the function arguments as a list, and pass it to do.call.
One can use deparse(substitute()) combination to extract the parameter name inside the function like this function
names_from_dots <- function(...) {
deparse(substitute(...))
}
data(iris)
data(swiss)
names_from_dots(iris)
#[1] "iris"
names_from_dots(swiss)
#[1] "swiss"
extracts the name of a data.frame passed in ... (dots) parameter.
But how can one extract every name of passed multiple data.frames
names_from_dots(swiss, iris)
[1] "swiss"
names_from_dots(iris, swiss)
[1] "iris"
When this only returns the name of the first object.
I wouldn’t use substitute here at all, it works badly with ...1. Instead, you can just capture the unevaluated dots using:
dots = match.call(expand.dots = FALSE)$...
Then you can get the arguments inside the dots:
sapply(dots, deparse)
1 Part of the reason is, I think, that substitute does completely different things when called with (a) an argument (which is a “promise” object) or (b) another object. ... falls somewhere in between these two.
You can try the following:
names_from_dots <- function(...) sapply(substitute(list(...))[-1], deparse)
names_from_dots(swiss, iris)
# [1] "swiss" "iris"
I am writing a function that receives two parameters: a data frame, and a function, and, after processing the data frame, summarizes it using the function parameter (e.g. mean, sd,...). My question is, how can I get the name of the function received as a parameter?
How about:
f <- function(x) deparse(substitute(x))
f(mean)
# [1] "mean"
f(sd)
# [1] "sd"
do.call may be what you want here. You can get a function name as character value, and then pass that and a list of arguments to do.call for evaluation. For example:
X<-"mean"
do.call(X,args=list(c(1:5)) )
[1] 3
Perhaps I'm misunderstanding the question, but it seems like you could simply have the function name as a parameter, and evaluate the function like normal within your function. This approach works fine for me. The ellipsis is for added parameters to your function of interest.
myFunc=function(data,func,...){return(func(data,...))}
myFunc(runif(100), sd)
And if you'd want to apply it to every column or row of a data.frame, you could simply use an apply statement in myFunc.
Here's my try, perhaps, you want to return both the result and the function name:
y <- 1:10
myFunction <- function(x, param) {
return(paste(param(x), substitute(param)))
}
myFunction(y, mean)
# [1] "5.5 mean"
Is there anyway I can loop through some set of objects and apply a function to each?
When I type ls() or objects(), it returns a list of object names. I could like to iterate through this list, identify those which are data.frame, and then run a function against each object.
How do I pass an entry from ls or objects through a function?
The answer given by #jverzani about figuring out which objects are data frames is good. So let's start with that. But we want to select only the items that are data.frames. So we could do that this way:
#test data
df <- data.frame(a=1:10, b=11:20)
df2 <- data.frame(a=2:4, b=4:6)
notDf <- 1
dfs <- ls()[sapply(mget(ls(), .GlobalEnv), is.data.frame)]
the names of the data frames are now strings in the dfs object so you can pass them to other functions like so:
sapply( dfs, function(x) str( get( x ) ) )
I used the get() command to actually get the object by name (see the R FAQ for more about that)
I've answered your qeustion above, but I have a suspicion that if you would organize your data frames into list items your code would be MUCH more readable and easy to maintain. Obviously I can't say this with certainty, but I can't come up with a use case where iterating through all objects looking for the data frames is superior to keeping your data frames in a list and then calling each item in that list.
You can get an object from its name with get or mget and iterate with one of the apply type functions. For example,
sapply(mget(ls(), .GlobalEnv), is.data.frame)
will tell you which items in the global environment are data frames. To use within a function, you can specify an environment to the ls call.
You can loop through objects in environment using "eapply".
Throwing in another solution to the mix using inherits. It basically (a) gets all objects from the current environment and (b) checks if they inherit from a data frame.
sapply(sapply(ls(), get), inherits, 'data.frame')
You can use the function get() to refer to an object by name
# Create some objects
df <- data.frame(a=1:10)
dl <- list(a=1, b=2, c=3)
# Use `ls()` to return a list of object names
lso <- ls()
# Use `get()` to refer to specific objects
class(get(lso[1]))
[1] "data.frame"
# Using an apply function to evaluate the class
lapply(lso, function(x) class(get(x)))
[[1]]
[1] "data.frame"
[[2]]
[1] "list"
You can use Filter with is.data.frame and ls in mget to get a named list of in this case of data.frame objects.
This list can then be used e.g. in lapply to apply each element of the list to a function.
L <- Filter(is.data.frame, mget(ls()))
lapply(L, nrow)