2

Reproducible example:

set.seed(1)
A <- round(runif(12, min = 1, max = 5))

> A
 [1] 1 2 2 4 3 4 3 4 5 3 4 5

expectedResult <- c(max(A[1], A[4]), max(A[2], A[5]), max(A[3], A[6]), max(A[7], A[10]), max(A[8], A[11]), max(A[9], A[12]))

> expectedResult
[1] 4 3 4 3 4 5

Each A needs to be considered as a collection of segments with 6 elements. For example, A here has 2 segments such as A[1:6] and A[7:12]. For each segment, the first 3 elements are compared with the next 3 elements. Therefore I need to take max(A[1],A[4]), max(A[2], A[5]), max(A[2], A[5]), max(A[3], A[6]), max(A[7], A[10]), max(A[8], A[11]), max(A[9], A[12]).

My original vector has way more elements than this example and therefore I need a much simpler approach to do this. In addition, speed is also a factor for the original calculation and therefore looking for a fast solution as well.

Rel_Ai
  • 581
  • 2
  • 11

3 Answers3

1

We could create a function to split the vector by 'n' elements, loop over the list, create a matrix with nrow specified as 2, use pmax to do elementwise max after converting to data.frame, return the output by unlisting the list

f1 <- function(vec, n) {
       lst1 <- split(vec, as.integer(gl(length(vec), n, length(vec))))
       unname(unlist(lapply(lst1, function(x) 
       do.call(pmax, as.data.frame(t(matrix(x, nrow = 2, byrow = TRUE)))))))
}

-output

> f1(A, 6)
[1] 4 3 4 3 4 5

If the length is not a multiple of 3 or 6, another option is to do a group by operation with tapply after splitting

unname(unlist(lapply(split(A, as.integer(gl(length(A), 6, 
    length(A)))), function(x) tapply(x, (seq_along(x)-1) %% 3 + 1, FUN = max))))
[1] 4 3 4 3 4 5

data

A <- c(1, 2, 2, 4, 3, 4, 3, 4, 5, 3, 4, 5)
akrun
  • 874,273
  • 37
  • 540
  • 662
1

Another option in base R:

a <- 6
unlist(tapply(A, gl(length(A)/a, a),
  function(x) pmax(head(x, a/2), tail(x, a/2))),, FALSE)
[1] 4 3 4 3 4 5

or even

a <- 6
unlist(tapply(A, gl(length(A)/a, a),
  function(x) do.call(pmax, data.frame(matrix(x, ncol = 2)))),, FALSE)
[1] 4 3 4 3 4 5
Onyambu
  • 67,392
  • 3
  • 24
  • 53
1

You can reshape the vector to a 3d array, split by column, and take the parallel max. This should be pretty efficient as far as base R goes.

do.call(pmax.int, asplit(`dim<-`(A, c(3,2,2)), 2))

[1] 4 3 4 3 4 5
Ritchie Sacramento
  • 29,890
  • 4
  • 48
  • 56