Passing in all arguments - r

Consider the following:
foo <- function(a = 1, b = 2, c = 3, d = 1, e = 2, f = 3, g = 4, h = 1) {
print(h)
bar(a = a, b = b, c = c, d = d, e = e, f = f, g = g)
foobar(c = c, e = e, g = g)
}
bar <- function(a, b, c, d, e, f, g) {
a + b + c + d + e + f * g
}
foobar <- function(c, e, g) {
if (c) {
print(g + e)
}
}
foo(1, 2, 3, 4,5, 6, 7, 8)
I have something similar to the above where I have subfunction calls that require a lot of the variables passed down from the level above it. Is there an easier way of doing lines 3 and 4 of this code, rather than manually listing out each variable each time it calls it?

Well, we can create a helper function to make this easier
call_match_args <- function(fun, data) {
fun <- match.fun(fun)
seeking <- names(formals(fun))
stopifnot(all(seeking %in% names(data)))
do.call(fun, data[seeking], envir=parent.frame())
}
this will take a function and a list and will pass all the values of the list that match the function parameters names as arguments. The do.call function takes care of turning the list into parameters.
Then we can change your foo function to look something like this
foo <- function(a = 1, b = 2, c = 3, d = 1, e = 2, f = 3, g = 4, h = 1) {
vars <- mget(ls())
print(vars$h)
call_match_args(bar, vars)
call_match_args(foobar, vars)
}
foo(1, 2, 3, 4,5, 6, 7, 8)
# [1] 8
# [1] 12
while bar and foobar can stay the same. The first step in the function it to take all the parameter values and put them in a list. Then you access them from that list and can pass that list to the call_match_args helper function.

Related

Unlist LAST level of a list in R

I have a list of list like ll:
ll <- list(a = list(data.frame(c = 1, d = 2), data.frame(h = 3, j = 4)), b = list(data.frame(c = 5, d = 6), data.frame(h = 7, j = 9)))
I want to unnest/unlist the last level of the structure (the interior list). Note that every list contains the same structure. I want to obtain lj:
lj <- list(a = (data.frame(c = 1, d = 2, h = 3, j = 4)), b = data.frame(c = 5, d = 6, h = 7, j = 9))
I have tried the following code without any success:
lj_not_success <- unlist(ll, recursive = F)
However, this code unlists the FIRST level, not the LAST one.
Any clue?
We may need to cbind the inner list elements instead of unlisting as the expected output is a also a list of data.frames
ll_new <- lapply(ll, function(x) do.call(cbind, x))
-checking
> identical(lj, ll_new)
[1] TRUE

How to concentrate function arguments into a vector in R by a function?

I have some R-function f, which fixes some parameters of some other function target (thanks to GKi for help):
target <- function(b1,b2,l1,l2,l3,o1,o2) return((b1+b2+l1+l2+l3+o1+o2)^2)
fixed <- c(b1 = 1, l1 = 2, l2 = 3, l3 = 4, o1 = 5)
variable <- c("o2","b2")
f <- function(fixed, variable) {
target_new <- function() {}
formals(target_new) <- setNames(rep(list(bquote()), length(variable)), variable)
for(i in variable) assign(i, as.symbol(i))
body(target_new) <- do.call("call", unlist(list("target", mget(variable), as.list(fixed))))
return(target_new)
}
f(fixed,variable)
> function (o2, b2)
> target(o2 = o2, b2 = b2, b1 = 1, l1 = 2, l2 = 3, l3 = 4, o1 = 5)
> <environment: 0x0000020a8e0c0c88>
I want to maximize target_new by nlm, so I need to concentrate its function arguments into a vector, i.e. the desired output of f(fixed,variable) is
> function (theta)
> target(o2 = theta[1], b2 = theta[2], b1 = 1, l1 = 2, l2 = 3, l3 = 4, o1 = 5)
How to modify the above code, so that the function can process the vector theta?
Please mind that the vectors fixed and variable can be of variable lengths.
You are making this too complicated.
f <- function(fixed, variable) {
function(theta) {
args <- c(as.list(theta), as.list(fixed))
names(args)[seq_along(variable)] <- variable
do.call(target, args)
}
}
fun <- f(fixed, variable)
#does it work?
all.equal(
nlm(fun, p = c(1, 2)),
nlm(function(theta) target(1,theta[2], 2, 3, 4, 5, theta[1]),
p = c(1, 2))
)
#[1] TRUE

The right way to pass a list of list to a function, with missing and/or irrelevant elements

What is a robust way of passing a list of list of arguments to a function, when not all arguments are used by the function?
Parameters are stored in a named list of named lists
params <- list("1" = list(a = 1, b = 2),
"2" = list(a = 3, b = 4, c = 5), # not all parameters will be used
"3" = list(a = 6, b = 7),
"4" = list(a = 8)) # some parameters will be missing
The function uses some of these parameters, but not necessarily all of them (list "2"). Also it has default values, so I'd like it to work even if only some of its values are passed (list "4").
f <- function(a = 0, b = 0)
print(paste0("a = ", a, ", b = ", b))
I don't know how to pass an excessively populated list:
do.call(f, params[["2"]])
## Error in (function (a = 0, b = 0) : unused argument (c = 5)
I would like to select and pass several lists at once. The expected output is something like what this loop produces:
selected <- c("1", "3")
for (i in selected)
do.call(f, params[[i]])
## [1] "a = 1, b = 2"
## [1] "a = 6, b = 7"
If you can allow optional arguments to your function
f <- function(a = 0, b = 0, ...) print(paste0("a = ", a, ", b = ", b))
for (i in seq_along(params)) {
do.call(f, params[[i]])
}
#[1] "a = 1, b = 2"
#[1] "a = 3, b = 4"
#[1] "a = 6, b = 7"
#[1] "a = 8, b = 0"

Unpack a list by duplicating elements longer than 1

I have the following list that I wish to unpack (aka expand) using only base R.
For example, I want to turn this:
b <- list(a = c(1, 2), b = 1, d = c(5, 7))
into the equivalent of:
list(a = 1, a = 2, b = 1, d = 5, d = 7)
I have this function that works if only one named element has length > 1 but not if there are multiple elements:
expand_list <- function(listx){
long_elements <- as.numeric(which(lapply(listx, length) > 1))
short_elements <- as.numeric(which(lapply(listx, length) == 1))
res <- lapply(long_elements, function(x){
as.list(setNames(listx[[x]], rep(names(listx)[x], length(listx[[x]]))))
})
expanded_elements <- res[[1]]
c(listx[short_elements], expanded_elements)
}
expand_list(b)
You can use stack followed by setNames to achieve that
y <- list(a = c(1, 2), b = 1, c = 2, d = c(5, 7))
x <- stack(y)
as.list(setNames(x$values, x$ind))

passing additional parameters to two function

I want to pass parameters to two functions. I try the ..., but seems the ... pass all the parameters to the first function. My trial code is below, but with errors.
f_add <- function(a = 1, b = 1){
return(a+b)
}
f_minus <- function(c = 1, d = 2){
return(c - d)
}
f_1 <- function(...){
f_add(...) + f_minus(...)
}
Errors:
f_1(a = 1, b =2 , c = 3, d = 4)
## Error in f_add(...) : unused arguments (c = 3, d = 4)
## Called from: f_add(...)
## Browse[1]> Q
So here I ask for any easy way to design the functions.
You can allow the function f_add and f_minus to take unnamed arguments, and ignore them:
f_add <- function(a = 1, b = 1, ...){
return(a+b)
}
f_minus <- function(c = 1, d = 2, ...){
return(c - d)
}
f_1 <- function(...){
f_add(...) + f_minus(...)
}
This admits your desired computation:
f_1(a=1, b=2, c=3, d=4)
## [1] 2
f_add <- function(a = 1, b = 1){
return(a+b)
}
f_minus <- function(c = 1, d = 2){
return(c - d)
}
f_1 <- function(a,b,c,d){
f_add(a,b) + f_minus(c,d)
}
f_1(a=1,b=100,c=2000,d=5)
2096

Resources