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).
Asked
Active
Viewed 40 times
-1

Gaspar
- 49
- 1
- 8
-
It's easier to help you if you provide a [reproducible example](https://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example) with sample input and desired output that can be used to test and verify possible solutions. – MrFlick Aug 25 '22 at 20:36
-
You're right. Say: V = [1 2 3 4 5]; X = 7; V[1] + V[2] = 1 + 2 = 3 <= 7; V[1] + V[2] + V[3] = 1 + 2 +3 = 6 <= 7; V[1] + V[2] + V[3] + V[4] = 1 + 2 + 3 + 4 = 10 > 7; So I want the algorithm to stop at 4, inform the value of 10, and tell me the number of iterations it took (again, in this case, 4). Hope it's clear! – Gaspar Aug 25 '22 at 20:37
-
I used X instead of M here, but it's the same. It's the value it has to exceed. – Gaspar Aug 25 '22 at 20:44
2 Answers
2
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)

Rui Barradas
- 70,273
- 8
- 34
- 66
-
I was comparing your fun_for vs my f.loop, no clue why, but the max of your function is high: Unit: microseconds expr min lq mean median uq max neval cld f.loop(v, val) 77.6 82.50 96.6310 85.20 88.00 440.5 1000 a fun_for(v, val) 70.7 75.20 93.0540 77.50 80.65 5389.6 1000 a (ie 440 vs 5389) – Will Aug 25 '22 at 21:35
-
Thank you very much, truly. But in reality I am looking for something much, much simpler. Using just ```for``` and ```while```. If somebody comes up with an idea for that, I'd be truly appreciated. – Gaspar Aug 25 '22 at 22:04
-
@Gaspar I don't understand this last comment, one of the functions uses only `while` and another uses only `for`. – Rui Barradas Aug 26 '22 at 04:42
1
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

Will
- 910
- 7
- 17
-
Thank you very much for your answer, but I need to do it using the while function! – Gaspar Aug 25 '22 at 20:52
-
@Gaspar Why do you need to do it using `while`, is it homework? If so, please edit the question with that information, not even in the question title you say that `while` is *needed*. – Rui Barradas Aug 25 '22 at 20:56
-
It's the syntax I use. And the title does say the name of the functions "while" and "for". But will make it clearer anyways. – Gaspar Aug 25 '22 at 21:00
-
2Gaspar> you're right, I ignored your requirements because I assumed it was a beginner mistake. R is a vectorial language. it does not make sense to do it with a loop. and the performance will kill you. but added with a loop to answer your question. – Will Aug 25 '22 at 21:07