1

Suppose I have the following code

b = 1:3
m = 5

for(j in 1:2){
  for(i in 1:5){
    print((1-i/m)* b[j] + (i/m)* b[j+1])
  }
}

If i print this i get the following output

[1] 1.2
[1] 1.4
[1] 1.6
[1] 1.8
[1] 2
[1] 2.2
[1] 2.4
[1] 2.6
[1] 2.8
[1] 3

However, now I would like to store this data into a single column vector. When i substitute print for an empty vector or list z[i] <- this ofcourse does not work. Does anyone know how to get the for loop value into a single column vector?

WHN
  • 27
  • 5

2 Answers2

1

We can initiate a vector and append the output to it

out <- c()
 for(j in 1:2){
  for(i in 1:5){
    out <- c(out, (1-i/m)* b[j] + (i/m)* b[j+1])
  }
}

df1 <- data.frame(out)

-output

df1
   out
1  1.2
2  1.4
3  1.6
4  1.8
5  2.0
6  2.2
7  2.4
8  2.6
9  2.8
10 3.0

Or another option is outer from base R

out <- c(t( outer(1:2, 1:5, FUN = function(j, i) (1-i/m)* b[j] + (i/m)* b[j+1])))

-ouptut

out
#[1] 1.2 1.4 1.6 1.8 2.0 2.2 2.4 2.6 2.8 3.0

Or use expand.grid (R 4.1.0)

expand.grid(j = 1:2, i = 1:5) |> 
      transform(out = (1-i/m)*b[j] + (i/m) * b[j + 1]) |> 
      subset(select = out)
   out
1  1.2
2  2.2
3  1.4
4  2.4
5  1.6
6  2.6
7  1.8
8  2.8
9  2.0
10 3.0

Benchmarks


j1 <- 1:200
i1 <- 1:500
# // outer 
system.time({
 out <- c(t( outer(j1, i1, FUN = function(j, i) (1-i/m)* b[j] + (i/m)* b[j+1])))

})
#  user  system elapsed 
#  0.004   0.000   0.004 

# // sapply

system.time({
out2 <- sapply(j1,function(j){
  sapply(i1,function(i){
    out <- (1-i/m)* b[j] + (i/m)* b[j+1]
    return(out)
  })
})
})
# user  system elapsed 
#  0.152   0.004   0.155 
akrun
  • 874,273
  • 37
  • 540
  • 662
0

Base R, sapply

b = 1:3
m = 5

df <- sapply(1:2,function(j){
  sapply(1:5,function(i){
    out <- (1-i/m)* b[j] + (i/m)* b[j+1]
    return(out)
  })
})

result <- c(df[c(1:5),c(1:2)]) 

Result

[1] 1.2 1.4 1.6 1.8 2.0 2.2 2.4 2.6 2.8 3.0

Speed test - sapply vs for loop

b = 1:10001
m = 5

> system.time({ 
+ df <- sapply(1:10000,function(j){
+   sapply(1:5,function(i){
+     out <- (1-i/m)* b[j] + (i/m)* b[j+1]
+     return(out)
+   })
+ })
+ })
   user  system elapsed 
   0.19    0.00    0.19 
 
> system.time({ 
+ out <- c()
+ for(j in 1:10000){
+   for(i in 1:5){
+     out <- c(out, (1-i/m)* b[j] + (i/m)* b[j+1])
+   }
+ }
+ })
   user  system elapsed 
   3.00    0.02    3.02 
  • *apply functions are usually NOT significantly faster than for loops. They actually call for loops inside them. The main advantage of using apply functions is for clarity and readability, not speed. Even nested applys do not outperform nested for loops. You example is quite convoluted, and, therefore, does not offer any advantages over the original nested for loop. – GuedesBF May 30 '21 at 21:56
  • 1
    The apply function also DOES NOT run simultaneous threads. – GuedesBF May 30 '21 at 21:58
  • 1
    @GuedesBF i just tried to run it with a timer and 1:10000 in the top loop, i got "0.19" sec for my code and 3.00 sec for the double for loop, if i add one extra zero my code is at 1.84 sec, while the loop does not finish, i was sure this had somthing to do with threads, but mabye it is the way the for loop has to overwrite the vector for each run https://imgur.com/2l2ZCtk – 1k monkeys and a single PC May 30 '21 at 22:41
  • @GuedesBF deleted my explanation, so i dont spread miss information, thank you – 1k monkeys and a single PC May 30 '21 at 23:10
  • There is some interesting discussion about performance of apply and loops: https://stackoverflow.com/questions/42393658/lapply-vs-for-loop-performance-r/42440872#42440872 https://stackoverflow.com/questions/2275896/is-rs-apply-family-more-than-syntactic-sugar – GuedesBF May 31 '21 at 00:12