Reputation: 28928
I want to replace the behaviour of sapply
with a for loop. (See further down for why, if interested.)
Here is a simplification of the sapply version of my code:
slow_function=function(n) c(n*n, 0, (-n)^n, -1, +1)
quick_analysis=function(res) res[1]+res[3]
results=sapply(1:8,function(n){
res=slow_function(n)
a=quick_analysis(res)
b=table(sign(res))
list(
a=a,
up=b['1'],
down=b['-1'],
level=b['0']
)
})
That gives me:
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
a 0 8 -18 272 -3100 46692 -823494 16777280
up 2 3 2 3 2 3 2 3
down 2 1 2 1 2 1 2 1
level 1 1 1 1 1 1 1 1
(That is good, though incidentally I actually want it transposed, with values of n as the rows, and a, up, down, level as the columns. But, no problem, I know how to do that.)
When I turn it into a for loop:
results=vector()
for(n in 1:8){
res=slow_function(n)
a=quick_analysis(res)
b=table(sign(res))
results[n]=list(
a=a,
up=b['1'],
down=b['-1'],
level=b['0']
)
}
then I get 8 warning messages like:
1: In results[n] = list(a = a, up = b["1"], down = b["-1"], level = b["0"]) :
number of items to replace is not a multiple of replacement length
And results is very different:
[[1]]
[1] 0
[[2]]
[1] 8
[[3]]
[1] -18
[[4]]
[1] 272
[[5]]
[1] -3100
[[6]]
[1] 46692
[[7]]
[1] -823494
[[8]]
[1] 16777280
I kind of understand what is happening. What I don't know is the magic incantation to get the result I want! I've tried initializing results to be matrix()
or list()
instead, with identical output.
ASIDE: Why do I want to use a for loop? I actually want to do two calculations per pass of the sapply loop. In other words only make 8 calls to slow_function
but return 16 rows of results. If sapply allowed it my code would be something like:
results=sapply(1:8,function(n){
res=slow_function(n)
a=quick_analysis(res)
b=table(sign(res))
list(
a=a,
up=b['1'],
down=b['-1'],
level=b['0']
)
res=-res #Modify res
a=quick_analysis(res)
b=table(sign(res))
list(
a=a,
up=b['1'],
down=b['-1'],
level=b['0']
)
})
Desired output: (sorry the formatting is off, I had to make it by hand)
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12] [,13] [,14] [,15] [,16]
a 0 0 8 -8 -18 18 272 -272 -3100 3100 46692 -46692 -823494 823494 16777280 -16777280
up 2 2 3 1 2 2 3 1 2 2 3 1 2 2 3 1
down 2 2 1 3 2 2 1 3 2 2 1 3 2 2 1 3
level 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
Upvotes: 1
Views: 1605
Reputation: 77096
sapply simplifies the result by default, when they all have the same length. Thus, you need to manually combine the various sublists that a for loop returns,
results2 = list()
for (n in 1:8){
res=slow_function(n)
a=quick_analysis(res)
b=table(sign(res))
results2[[n]] = list(
a=a,
up=b['1'],
down=b['-1'],
level=b['0']
)
}
do.call(cbind, results2)
Upvotes: 1
Reputation: 109874
This is a shot in the dark for how to accomplish this without data and knowing what your after:
slow_function=function(n) c(n*n, 0, (-n)^n, -1, +1)
quick_analysis=function(res) res[1]+res[3]
results=lapply(1:8,function(i){
res=slow_function(i)
FUN <- function(res.in) {
a=quick_analysis(res.in)
b=table(sign(res.in))
data.frame(
a=a,
up=b['1'],
down=b['-1'],
level=b['0']
)
}
data.frame(id=c("p", "n"), it=i, rbind(FUN(res), FUN(-res)))
})
DAT <- do.call(rbind, results)
with(DAT, DAT[order(id, it), ]) #maybe the order you're after
EDIT:
This will give you what you want then (the indexing and id was never necessary I did it because I didn't know your desired output; you can remove thema s you see fit):
rownames(DAT) <- NULL
t(DAT[, -c(1:2)])
Upvotes: 2