Reputation: 33
I'm working in R and would like to pass a vector to a function. The vector gives the maximum values for a series of for loops. If the vector is (3,4,6,5), then the following code should be run. So the number of for loops depends on the length of the vector that is passed to the function. Then for each possibility, the counters are input into another function fn. Provided an example for a possible fn below.
S=0
fn = function(x){sum(x^2)}
for (i in 0:3){
for (j in 0:4){
for (k in 0:6){
for (l in 0:5){
S=S+fn(c(i,j,k,l))
}
}
}
}
I believe recursion is the way to go here, but I haven't had any luck figuring it out, and most of the recursion examples I've seen seem to be at a very high or very low level.
Any idea what the best way to approach this problem is?
Upvotes: 3
Views: 1595
Reputation: 47
@Dason's answer is very nice but fails when all elements of vec
are equal (because mapply
then converts the result from a list to a matrix, whereas do.call
requires a list). This can be rectified by adding SIMPLIFY = FALSE
:
class(mapply(seq, 0, c(2, 2)))
[1] "matrix"
class(mapply(seq, 0, c(2, 2), SIMPLIFY = FALSE))
[1] "list"
The amended solution is then
f <- function(vec, fn){
vecs <- mapply(seq, 0, vec, SIMPLIFY = FALSE)
tmp <- do.call(expand.grid, vecs)
tmp <- apply(tmp, 1, fn)
sum(tmp)
}
fn = function(x){sum(x^2)}
f(c(3, 4, 6, 5), fn = fn)
Upvotes: 0
Reputation: 49640
I like @Dason's version using expand.grid
, but here is a recursive version for cases when that approach may not work, or for general enlightenment:
recfun <- function(a,b) {
S <- 0
if(length(b)) {
for( i in seq(0,b[1]) ) {
S <- S + Recall( c(a,i), b[-1] )
}
} else {
return(fn(a))
}
S
}
recfun( numeric(0), c(3,4,6,5) )
For practical use you may want to wrap this in another function that that takes the vector of interest and passes it to the function as b
with the empty vector as a
.
Upvotes: 1
Reputation: 61903
No need to use loops
f <- function(vec, fn){
vecs <- mapply(seq, 0, vec)
tmp <- do.call(expand.grid, vecs)
tmp <- apply(tmp, 1, fn)
sum(tmp)
}
fn = function(x){sum(x^2)}
f(c(3, 4, 6, 5), fn = fn)
Upvotes: 7