Suppose I have a vector x
with n
elements. I want to use any vectorised function, say cumprod
, on every alternate number of x
, i.e. every 1, 3, 5 and so on and another on 2, 4, 6 and so on. I am adding a reprex and code tried. The code works, but it seems I am unnecessarily taking a long route and code can be shortened. Can it be?
x <- 5:14
cumprod((x * (seq_along(x) %% 2)) + (seq_along(x)-1) %% 2) * seq_along(x) %% 2 +
cumprod((x * ((seq_along(x)-1) %% 2)) + seq_along(x) %% 2) * (seq_along(x)-1) %% 2
#> [1] 5 6 35 48 315 480 3465 5760 45045 80640
Here cumprod
is just an example function. I may have to use other functions in alternate sequence as well.
lapply() function in R Programming Language is used to apply a function over a list of elements. lapply() function is used with a list and performs the following operations: lapply(List, length): Returns the length of objects present in the list, List.
Functions present in the apply family are the ones that allow us to manipulate data frames, arrays, matrices, vectors. These functions are alternative to the loops. However, are more efficient than loops as functions are faster at the execution level. These functions reduce the need for explicitly creating a loop in R.
The sum() is a built-in R function that calculates the sum of a numeric input vector. It accepts a numeric vector as an argument and returns the sum of the vector elements. To calculate the sum of vectors in R, use the sum() function.
We could do this in a concise way with rowCumprods
after creating a matrix
(assuming the vector
is of even length)
library(matrixStats)
c(rowCumprods(matrix(x, nrow = 2)))
-output
[1] 5 6 35 48 315 480 3465 5760 45045 80640
if it can be odd length, then just append an NA
at the end
c(rowCumprods(matrix(c(x, list(NULL, NA)[[1 +
(length(x) %%2 != 0)]]), nrow = 2)))
-output
[1] 5 6 35 48 315 480 3465 5760 45045 80640
Or we can do this in a generalized way with ave
(works both with even/odd lengths)
ave(x, seq_along(x) %% 2, FUN = cumprod)
[1] 5 6 35 48 315 480 3465 5760 45045 80640
Select odd (c(TRUE, FALSE)
) or even (c(FALSE, TRUE)
) indices. Weave the two resulting vectors (c(rbind
)
c(rbind(cumprod(x[c(TRUE, FALSE)]), cumprod(x[c(FALSE, TRUE)])))
# [1] 5 6 35 48 315 480 3465 5760 45045 80640
To handle also odd vector length, you need to truncate the result to length of the vector.
x = 1:5
c(rbind(cumprod(x[c(TRUE, FALSE)]), cumprod(x[c(FALSE, TRUE)])))[1:length(x)]
# [1] 1 2 3 8 15
There will be a warning when the shorter result vector, corresponding to the even indices (which has one element less), is recycled in the rbind
step.
One option for both even and odd number of elements could be:
c(t(apply(matrix(x, 2, sum(seq_along(x) %% 2)), 1, cumprod)))[1:length(x)]
With x <- 1:5
:
[1] 1 2 3 8 15
With x <- 1:6
:
[1] 1 2 3 8 15 48
Or a less effective option, however, without any warnings:
y <- Reduce(`c`, sapply(split(setNames(x, seq_along(x)), !seq_along(x) %% 2), cumprod))
y[order(as.numeric(names(y)))]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With