0

I tried to create a repeat loop function based on logical case as follow:

n=5    # number of element in lambda
t=10   # limit state
lambda=c(runif(n,2,4)) #vector to be tested


tes=function(x)
{
  if(x>=t) {a=0;b=0;c=0} 
  else
  {  
    repeat
    {
      a=runif(1,0.5,0.8)
      b=runif(1, 5, 8)
      c=x+a+b
      print(a)
      print(b)
      if (c>=t) {break}
    }
  }
return(list(a,b,c))
}

I need to save all of the repeat loop iterations output into an object in the workspace to be used afterwards. however my function only save the latest value of the iterations. here's the example of iteration for lambda[1]: The iteration:

[1] 0.6714837
[1] 5.840948
[1] 0.7914275
[1] 7.264076

The saved result in the list:

[[1]]
[[1]][[1]]
[1] 0.7914275

[[1]][[2]]
[1] 7.264076

[[1]][[3]]
[1] 11.03819

how to save each of the result per iterations in the output list? I’ve looked through other thread, but I haven’t found a suitable solution for my case yet. Thank you.

mnx
  • 45
  • 5

4 Answers4

1

You can save the intermediate results in a list, then return it (loop_results). See below. I have also formatted a bit your code so that, intermediate results are printed in a more intelligible/compact way, and the returned list is named.

tes <- function(x) {
  if(x>=t) {
    a=0;b=0;c=0
    } else {
      loop_results <- list()
      i=0
    repeat
    {
      i <- i+1
      a=runif(1,0.5,0.8)
      b=runif(1, 5, 8)
      c=x+a+b
      cat("iteration ", i, "a: ", a, "b: ", b, "\n")
      loop_results[[i]] <- list(a=a, b=b, c=c)
      if (c>=t) {break}
    }
  }
  return(list(a=a, b=b, c=c, loop_results=loop_results))
}
Vincent Bonhomme
  • 7,235
  • 2
  • 27
  • 38
1

You can accumulate the results onto a data.frame.

I would also recommend you not assign identifiers like c and t, since those are built-in functions which can be masked by locals, especially if you're passing around functions as arguments, such as do.call(c,...).

I also suggest that it's probably appropriate to pass the limit state variable as another argument to the function.

tes <- function(x,lim) {
    res <- data.frame(a=double(),b=double(),c=double());
    if (x >= lim) {
        res[1L,] <- c(0,0,0);
    } else {
        i <- 1L;
        repeat {
            ta <- runif(1L,0.5,0.8);
            tb <- runif(1L,5,8);
            tc <- x+ta+tb;
            res[i,] <- c(ta,tb,tc);
            print(ta);
            print(tb);
            if (tc >= lim) break;
            i <- i+1L;
        };
    };
    return(res);
};

Demo:

set.seed(5L);
n <- 5L; ## number of elements in lambda
lambda <- runif(n,2,4); ## vector to be tested
lambda;
## [1] 2.400429 3.370437 3.833752 2.568799 2.209300
res <- lapply(lambda,tes,10);
## [1] 0.7103172
## [1] 6.58388
## [1] 0.7423806
## [1] 7.8695
## [1] 0.5331359
## [1] 5.819855
## [1] 0.647154
## [1] 5.955212
## [1] 0.6677518
## [1] 5.787779
## [1] 0.5605626
## [1] 6.162577
## [1] 0.7663609
## [1] 6.664768
## [1] 0.7526538
## [1] 7.670621
## [1] 0.7162103
## [1] 5.634021
## [1] 0.5677152
## [1] 5.419951
## [1] 0.6439742
## [1] 6.312236
## [1] 0.7897892
## [1] 5.425742
## [1] 0.7864937
## [1] 6.334192
## [1] 0.5178087
## [1] 5.825448
## [1] 0.5093445
## [1] 5.043447
## [1] 0.6461507
## [1] 6.785455
## [1] 0.6793559
## [1] 6.193042
## [1] 0.6190491
## [1] 7.448228
res;
## [[1]]
##           a       b         c
## 1 0.7103172 6.58388  9.694626
## 2 0.7423806 7.86950 11.012310
##
## [[2]]
##           a        b         c
## 1 0.5331359 5.819855  9.723428
## 2 0.6471540 5.955212  9.972803
## 3 0.6677518 5.787779  9.825968
## 4 0.5605626 6.162577 10.093577
##
## [[3]]
##           a        b        c
## 1 0.7663609 6.664768 11.26488
##
## [[4]]
##           a        b        c
## 1 0.7526538 7.670621 10.99207
##
## [[5]]
##            a        b         c
## 1  0.7162103 5.634021  8.559531
## 2  0.5677152 5.419951  8.196967
## 3  0.6439742 6.312236  9.165510
## 4  0.7897892 5.425742  8.424831
## 5  0.7864937 6.334192  9.329986
## 6  0.5178087 5.825448  8.552557
## 7  0.5093445 5.043447  7.762092
## 8  0.6461507 6.785455  9.640906
## 9  0.6793559 6.193042  9.081698
## 10 0.6190491 7.448228 10.276578
bgoldst
  • 34,190
  • 6
  • 38
  • 64
  • thanks! it works just as what I need and thanks also for notifying me the variables name issue, i know for the c but not for the t – mnx Mar 26 '16 at 20:45
0

A similar problem is faced in this question, that I hope you find useful. So, you should insert a cumulative function inside of your's, as in the following example. It simulate a game where, in case of victory you earn money, otherwise you will lose it. This procedure stores your savings fluctuations during all the process.

x <- y <- 10

while (x > 0) {
  if (rbinom(1, 1, 0.5) == 1) {
    x <- x + 10
  } else {
    x <- x - 1
  }
  y <- c(y, x)
}

Otherwise, if your problem goes on a superior dimensional level, you could try a vectorized approach, which is much faster. But for your problem the approach exposed should be fine.

Community
  • 1
  • 1
Worice
  • 3,847
  • 3
  • 28
  • 49
0

I took the liberty to add an argument in the function and a "maximum iteration" argument coupled with a warning. i think the optimal result form is the data frame for vectors a, b, and c.

Then, to apply it on a vector, I propose to use an lapply function.

n <- 5                    # number of element in lambda
limitstate <- 10          # limit state
lambda <- c(runif(n,2,4)) #vector to be tested

tes <- function(x, t, maxiter = 1000) {
  if( x >= t) {
    return(data.frame(a=0, b=0, c=0))
  } else {
    iter <- 1
    a <- c()
    b <- c()
    c <- c()
    repeat {
      a[iter] <- runif(1, 0.5, 0.8)
      b[iter] <- runif(1, 5, 8)
      c[iter] <- x + a[iter] + b[iter]
      if (c[iter] >= t) break
      iter <- iter+1
      if (iter >= maxiter) {
        warning("Maximum iteration reached")
        break
      }
    }
  }
  return(data.frame(a=a,b=b,c=c))
}

tes(2, 10)
lapply(lambda, tes, t=limitstate)
Vincent Guillemot
  • 3,394
  • 14
  • 21