Search code examples
c++rrcpp

C++ or Rcpp: comparison of two vectors without loop


I am a novice in C++ and Rcpp, and I am wondering how to compare each element of two different vectors without loop at one time.

My goal is to change the element of v1 by referencing other vector.`

Current code is

v1 = {6,7,8,9,10}
v2 = {2,4,6,8,10}
v3 = {a,b,a,b,c}
v4 = {0,0,0,0,0}
v5 = {a,b,c}
v6 = {1,2,3}

for (i in 1:5){
  if (v1[i] > v2[i]){
    for (j in 1:3){
      if (v5[j] == v3[i]){
        v4[i] = v2[i] + v6[j]
          if (v1[i] > v4[i]){
            v1[i] = v4[i]
          }
      }
    }
  }
}  

The result sould be

v1 = {3,6,7,9,10}

In fact, v1, v2, v3, v4 and v5, v6 are the different dataframe in R. Each element of v1 is compared to v2. If an element i in v1 is larger than i element in v2, the element of v1 becomes a sum of i element of v1 and element of v6 by corresponding v3 & v5. Then the newly estimated value v4[i] is compared to v1[i].

I have ta large number of cases in v1~v5 and v5~v6. In this case, using loop takes a long time. Is it possible to compare the different vectors without loop? or how to estimate and reference the other vector's element?


Solution

  • I do not see the need to use Rcpp or C++ here. The way I understand your requirements, you are trying to manipulate two sets of equal length vectors. For a "set of equal length" vectors one normally uses a data.frame or one of its extensions. Here I am using base R, data.table and dplyr with tibble. See for yourself which syntax you prefer. Generally speaking, data.table will most likely be faster for large data sets.

    Setup data:

    v1 <- c(6,7,8,9,10)
    v2 <- c(2,4,6,8,10)
    v3 <- c("a","b","a","b","c")
    v5 <- c("a","b","c")
    v6 <- c(1,2,3)
    

    Base R:

    df1 <- data.frame(v1, v2, v3)
    df2 <- data.frame(v5, v6)
    
    df1 <- merge(df1, df2, by.x = "v3", by = "v5")
    df1$v4 <- df1$v2 + df1$v6
    df1$v1 <- ifelse(df1$v1 > df1$v2 & df1$v1 > df1$v4, df1[["v4"]], df1[["v1"]])
    df1
    #>   v3 v1 v2 v6 v4
    #> 1  a  3  2  1  3
    #> 2  a  7  6  1  7
    #> 3  b  6  4  2  6
    #> 4  b  9  8  2 10
    #> 5  c 10 10  3 13
    

    data.table:

    library(data.table)
    dt1 <- data.table(v1, v2, v3, key = "v3")
    dt2 <- data.table(v5, v6, key = "v5")
    
    dt1[dt2, v4 := v2 + v6]
    dt1[v1 > v2 & v1 > v4, v1 := v4]
    dt1
    #>    v1 v2 v3 v4
    #> 1:  3  2  a  3
    #> 2:  7  6  a  7
    #> 3:  6  4  b  6
    #> 4:  9  8  b 10
    #> 5: 10 10  c 13
    

    dplyr:

    suppressPackageStartupMessages(library(dplyr))
    t1 <- tibble(v1, v2, v3)
    t2 <- tibble(v5, v6)
    t1 %>% 
      inner_join(t2, by = c("v3" = "v5")) %>%
      mutate(v4 = v2 + v6) %>%
      mutate(v1 = case_when(
        v1 > v2 & v1 > v4 ~ v4,
        TRUE ~ v1
      ))
    #> # A tibble: 5 x 5
    #>      v1    v2 v3       v6    v4
    #>   <dbl> <dbl> <chr> <dbl> <dbl>
    #> 1     3     2 a         1     3
    #> 2     6     4 b         2     6
    #> 3     7     6 a         1     7
    #> 4     9     8 b         2    10
    #> 5    10    10 c         3    13
    

    Created on 2019-04-19 by the reprex package (v0.2.1)

    The general idea is always the same:

    • join the two tables on the character column
    • create new column v4 as sum of v2 and v6
    • update v1 to the value of v4 where v1 > v2 and v1 > v4

    Note that base R and data.table do not preserve the order, so it would make more sense to put the output into an additional column.