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.
fun
uses vectorisedcumsum
to sum the vector;- 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