Creating a function in R with variable number of arguments,
d <- function(...){
x <- list(...) # THIS WILL BE A LIST STORING EVERYTHING:
sum(...) # Example of inbuilt function
}
d(1,2,3,4,5)
[1] 15
Passing variable number of arguments to R function
We can use do.call
. args
is a vector, do.call
needs a list of arguments, we can convert args
to list using as.list
.
do.call(test, as.list(args))
#[1] 4
Creating a variable number of arguments, function
So from what I've gathered, you want to have a list with x dataframes and find the maximum value of all observations and all variables in each dataframe.
Why don't you do the following:
# Create list with 10 dataframes
df_list <- list()
for (i in 1:10) {
df_list[[i]] <- data.frame(matrix(rnorm(100), ncol = 10))
colnames(df_list[[i]]) <- LETTERS[1:10]
}
# Find maximum value of all data.frames
sapply(df_list, FUN = max)
This creates a list with 10 dataframes, each with 10 observations and 10 variables. Then it loops over every data.frame to obtain the maximum value of each of those. At the end, a vector with the maximum values is returned.
How to provide dynamic number of arguments to a function inside a function in R?
If the change the apply
to do.call
, it would work as expected. Note that apply
with MARGIN = 2
, loop over the columns of 'df' individually, whereas the 'f1' needs the values of all those available columns (or else use the default values) to calculate the ((a + b) * c
)
f2 <- function(...){
arglist = list(...)
df = expand.grid(arglist)
do.call(f1, df)
}
and the f1
f1 <- function(a=1,b=1,c=2){
(a+b)*c
}
-testing
> f2(a = 10)
[1] 22
> f2(c = 10)
[1] 20
> f2(a = 5, c= c(5, 10))
[1] 30 60
Use variables as arguments in functions in R
Using the tidyverse
:
stp_f<-function(ivar,idur,ie){
x <- mydata %>%
group_by(get(ivar)) %>%
summarise(
sumdur = sum(get(idur)),
sumev = sum(get(ie)),
failrate = sumev / sumdur
) %>%
rename(var = `get(ivar)`)
x
}
stp_f("sex","adur","ae")
stp_f("sex","bdur","be")
stp_f("sex","cdur","ce")
Outputs:
> stp_f("sex","adur","ae")
# A tibble: 2 x 4
var sumdur sumev failrate
<chr> <dbl> <dbl> <dbl>
1 female 6 2 0.333
2 male 80 3 0.0375
> stp_f("sex","bdur","be")
# A tibble: 2 x 4
var sumdur sumev failrate
<chr> <dbl> <dbl> <dbl>
1 female 61 1 0.0164
2 male 101 3 0.0297
> stp_f("sex","cdur","ce")
# A tibble: 2 x 4
var sumdur sumev failrate
<chr> <dbl> <dbl> <dbl>
1 female 60 1 0.0167
2 male 178 2 0.0112
How to write a function with an unspecified number of arguments where the arguments are column names
1) Wrap the code in eval(substitute(...code...)) like this:
example.fun <- function(data, ...) {
eval(substitute(within(data, pasted <- paste(...))))
}
# test
df <- data.frame(x = c(1, 2), y = c("a", "b"))
example.fun(df, x, y)
## x y pasted
## 1 1 a 1 a
## 2 2 b 2 b
1a) A variation of that would be:
example.fun.2 <- function(data, ...) {
data.frame(data, pasted = eval(substitute(paste(...)), data))
}
example.fun.2(df, x, y)
2) Another possibility is to convert each argument to a character string and then use indexing.
example.fun.3 <- function(data, ...) {
vnames <- sapply(substitute(list(...))[-1], deparse)
data.frame(data, pasted = do.call("paste", data[vnames]))
}
example.fun.3(df, x, y)
3) Other possibilities are to change the design of the function and pass the variable names as a formula or character vector.
example.fun.4 <- function(data, formula) {
data.frame(data, pasted = do.call("paste", get_all_vars(formula, data)))
}
example.fun.4(df, ~ x + y)
example.fun.5 <- function(data, vnames) {
data.frame(data, pasted = do.call("paste", data[vnames]))
}
example.fun.5(df, c("x", "y"))
How to obtain a variable number of arguments by ... or by a list in R
You can handle the direct input of data frames, both named and unnamed, like this:
helper_df_compare = function( ..., a_default_arg = "def" ){
dots <- rlang::list2(...)
args <- as.list(match.call())[-1]
if(is.null(names(dots))) names(dots) <- rep('', length(dots))
for(i in seq_along(dots)) {
if(!nzchar(names(dots)[i])) names(dots)[i] <- as.character(args[[i]])
}
rbind(
do.call(janitor::compare_df_cols, c(dots, return = "mismatch")) %>%
mutate( column_name = paste("!!!", column_name) ),
do.call(janitor::compare_df_cols, c(dots, return = "match"))
) %>%
mutate_all( ~str_replace_all(.,c(
"integer"="int", "numeric"="num", "character"="chr", "factor"="fct",
"POSIXct, POSIXt"="POSIXct"
) ) )
}
This allows
helper_df_compare(people, people2, people3)
#> column_name people people2 people3
#> 1 !!! age int num int
#> 2 height num num num
#> 3 lastnames chr chr chr
#> 4 names chr chr chr
and this:
helper_df_compare(A = people, B = people2, C = people3)
#> column_name A B C
#> 1 !!! age int num int
#> 2 height num num num
#> 3 lastnames chr chr chr
#> 4 names chr chr chr
Related Topics
R: How to Select Files in Directory Which Satisfy Conditions Both on the Beginning and End of Name
Setting Ld_Library_Path from Inside R
Export All User Inputs in a Shiny App to File and Load Them Later
Rjava Is Not Picking Up the Correct Java Version
How to Remove All Rows from a Data.Frame
How to Calculate the Area of Polygon Overlap in R
How to Put a Box and Its Label in the Same Row? (Shiny Package)
Mapping Specific States and Provinces in R
Faster Way to Find the First True Value in a Vector
Import Multiple Text Files in R and Assign Them Names from a Predetermined List
What Are the Caveats of Using Source Versus Parse & Eval
Shade (Fill or Color) Area Under Density Curve by Quantile
Data.Table VS Plyr Regression Output
Plot Margin of PDF Plot Device: Y-Axis Label Falling Outside Graphics Window
Calculate Mean by Group Using Dplyr Package