Home > OS >  while and for in R
while and for in R

Time:08-26

I want to creat an alogrithm in R using while and for such that, given a vector V and an integer M, sums the elements of the vector V until that sum exceeds M, and I want it to inform the value that exceeded M as well as how many repetitions it took in order to exceed such number (i.e., how many elements of the vector did it summed).

CodePudding user response:

Here are three functions.

  1. fun uses vectorised cumsum to sum the vector;
  2. The other two have self-descriptive names.

They all return a named vector with the iterations count and the first sum exceeding m.

fun <- function(v, m) {
  i <- which(cumsum(v) < m)
  if(length(i)   1L < length(v))
    i <- c(i, length(i)   1L)
  c(Iter = length(i), Sum = sum(v[i]))
}
fun_while <- function(v, m) {
  Sum <- 0L
  Iter <- 0L
  while(Iter < length(v)) {
    Iter <- Iter   1L
    Sum <- Sum   v[Iter]
    if(Sum > m) break
  }
  c(Iter = Iter, Sum = Sum)
}
fun_for <- function(v, m) {
  Sum <- 0L
  for(i in seq_along(v)) {
    Sum <- Sum   v[i]
    if(Sum > m) break
  }
  if(is.null(i))   i <- 0L
  c(Iter = i, Sum = Sum)
}

V <- 1:5
M <- 7
fun(V, M)
#> Iter  Sum 
#>    4   10
fun_while(V, M)
#> Iter  Sum 
#>    4   10
fun_for(V, M)
#> Iter  Sum 
#>    4   10

V <- 1:5
M <- 20
fun(V, M)
#> Iter  Sum 
#>    5   15
fun_while(V, M)
#> Iter  Sum 
#>    5   15
fun_for(V, M)
#> Iter  Sum 
#>    5   15

V <- 1:10
M <- 42
fun(V, M)
#> Iter  Sum 
#>    9   45
fun_while(V, M)
#> Iter  Sum 
#>    9   45
fun_for(V, M)
#> Iter  Sum 
#>    9   45

V <- NULL
M <- 7
fun(V, M)
#> Iter  Sum 
#>    0    0
fun_while(V, M)
#> Iter  Sum 
#>    0    0
fun_for(V, M)
#> Iter  Sum 
#>    0    0

Created on 2022-08-25 by the reprex package (v2.0.1)

CodePudding user response:

both looping and vectorial way. benchmark added for curiosity.

library(data.table)
library(microbenchmark)
library(ggplot2)

val <- 2e6
v <- seq(1, 1e6, 2)

f.vec <- function(v, val) {
  dt <- as.data.table(v)
  dt[, cs := cumsum(v)]
  idx <- dt[cs <= val, .N]
  valnext <- dt[idx 1, .(v)]
  list(rep = idx, valnext = valnext)
}

f.loop <- function(v, val) {
  idx <- 1
  total <- 0
  for (el in v) {
    total <- total   el
    if (total >= val) {
      break
    } 
    idx <- idx   1
  }
  list(rep = idx-1, valnext = v[idx])
}

f.vec(v, val)
#> $rep
#> [1] 1414
#> 
#> $valnext
#>       v
#> 1: 2829
f.loop(v, val)
#> $rep
#> [1] 1414
#> 
#> $valnext
#> [1] 2829

tm <- microbenchmark(f.vec(v, val), f.loop(v, val), times=1000L)
autoplot(tm)
#> Coordinate system already present. Adding new coordinate system, which will replace the existing one.

tm
#> Unit: microseconds
#>            expr    min     lq      mean median     uq     max neval cld
#>   f.vec(v, val) 4848.5 5163.9 7856.0267 5643.6 9146.1 66502.9  1000   b
#>  f.loop(v, val)   72.7   75.8   81.1795   79.1   81.2   255.2  1000  a

Created on 2022-08-25 with reprex v2.0.2

  • Related