Search code examples
rloopswhile-loopvectorization

How to vectorize the output created by a while loop in R?


I would like to get the results from a while loop as a vector. My code looks like this and nld is just some numeric data and lk represents yearly rate of a country:

 i<-1
  while (i<=length(nld)) {
    lk<-((nld[i+1]-nld[i])/nld[i])*100
    i <- i+1
    print(lk)   }

But the output looks like this:

> [1] 2.34391
[1] 4.421947
[1] 0.6444809
[1] 11.29308
[1] 4.282817
[1] 1.773046
[1] 5.443044
[1] 6.332272
[1] 9.207917
[1] 6.173719
[1] 5.449088
[1] 3.977678
[1] 7.697896
[1] 6.313985
[1] 1.449447
[1] 5.149968
[1] 1.840442
[1] 2.628424
[1] 2.269874
[1] 4.195588
[1] -2.868499
[1] -2.764851
[1] 0.216549
[1] 1.907869
[1] -2.13202
[1] 4.637701
[1] 1.051423
[1] 3.946669
[1] 4.332345
[1] 6.260946
[1] 3.113528
[1] 1.537622
[1] 3.075729
[1] 2.925915
[1] 5.146445
[1] 6.129935
[1] 5.185049
[1] 3.45909
[1] 7.835161
[1] 9.649116
[1] 1.311721
[1] 0.3325002

... etc.

and i can't get and plot these results from this loop. I would be appreciated if someone could enlighthen me. Thanks in advance.


Solution

  • i <- 1
    result <- c()
    while (i<=length(nld)) {
        lk<-((nld[i+1]-nld[i])/nld[i])*100
        i <- i+1
        result <- c(result, lk)   } # this collects `lk`  in the vector `result`.
    

    But what you are doing is very C-ish (or C++-ish). Whenever in R or Python you see indexes and index incrementation, in 99% of the cases there is a better expression in R or Python.

    E.g. in this case, you are actually going through nld using a while loop - that is not good.

    In R you would use Map() - which can iterate in parallel through vectors/lists.

    nld <- 1:10
    result <- Map(f=function(x, y) (x - y)/y * 100,
                  nld[2:length(nld)],
                  nld)
    

    But there is a mistake in your original code. You loop from i=1 to i=length(nld) but requires nld[i+1]. The i+1 would in the last case demand sth not existing. so it should be while (i < length(nld)) { ... and

    result <- Map(f=function(x, y) (x - y)/y * 100,
                  nld[2:length(nld)],
                  nld[1:(length(nld)-1)])
    

    Or even more R-ish: use vectorization:

    f <- function(x, y) (x-y)/y*100
    > f(nld[2:length(nld)], nld[1:(length(nld)-1)])
    ## [1] 100.00000  50.00000  33.33333  25.00000  20.00000  16.66667  14.28571
    ## [8]  12.50000  11.11111
    

    Or:

    f <- function(vec) {
      vec1 <- vec[2:length(vec)]
      vec2 <- vec[1:(length(vec)-1)]
      (vec1 - vec2)/vec1 * 100 # this uses vectorization!
    }
    
    f(nld)