Вопрос

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  
Это было полезно?

Решение

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)

Другие советы

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)])
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top