Search code examples
rvectorconditional-statementsmaxpairwise

Return maximum of conditionally selected pairs from a vector in R


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.


Solution

  • 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)